Kotlin to support package protected visibility


#6

I’m not sure that package private would be sufficient. There is a wider case for “logical” visibility rules that are independent from the run-time visibility. In particular, the use of inline functions can cause classes and functions to have to be visible that actually would not need to be. Perhaps the inline function is a simple wrapper, but why not make it that the only access is through the wrapper. In particular, visibility should be mainly about the visibility in code, not about visibility to the compiler or at run-time. When using the jvm, this may imply some compromises (perhaps marking the methods / classes involved as synthetic and giving them names with illegal characters (from a java perspective, not jvm perspective) in the name would solve the compatibility issue.) For compatibility in those cases, there could be a java only implementation of the inline function that is not inline.


#7

Guys i cant really understand why you want to stick with such decision, i just described simple use case where you have just sample 10 files with pretty names perfectly doing their job and only one of them is visible to the same modul, i dont get any stupid autocomplete to a class that is not ment to be used for anything else…

In java we did this very pretty, we take care of the incapsulation it is never envorced, but you have it all perfectly spread across files (actually i think they should allow us to define package visibility like a.b b is not visible out of a etc…) but watever, to do this simple thing in kotlin i have to put all the souce code in one file… is that pretty? no everything else is this one thing isnt… and i do really use a lot this package protected fictional incapsulation…

If someone wants this strict incapsulation go ahead and do the single file with 9 private classes… but give me an option to have the thing in old ways, it does not break anything. I wonder how big kotlin projects look like at jetbrains? are there many classes in one file? or all classes are just visible to everyone in the module? or maybe simple 10 class utility is a separate kotlin module which is then attached through gradle or something?

The thing is that everything else you guys did makes writing code better its less code you have to read and its compact… but putting lot of stuff in one file is not readable.


#8

if i understand it correctly your suggestion implies that if i want to have 1 public class and 9 package protected that do the actual job in java, i have to create a separate project declare those 9 as internal and then have this project compiled and accessible using Maven or Gradle or whatever one uses for the DI?

Imho that’s an overkill…

Note that if i do 10 classes in one file 9 private i wont even be able to test those 9.

I personally never saw any code working around package protected access using same package name… it will just differ from your regular package structure and will constantly remind devs “fix me this is a shitcode”.


#9

How am I supposed to do unit / whitebox testing properly? I want to write test code which tests class-internal functionality which I do not want to expose to other classes except my test class at all.

The package protected visibility is an excellent way to achieve this. Whereas Kotlin now requires me to make these methods effectively public and litter the visible API of my component all-over the project be able to test them.

In my view internal is more or less public as it has a much larger scope. Most projects have sth. around 1 - 5 “modules” in the Kotlin sense.

Really strongly asking/advocating for package-local visibility here.


#10

I agree that this is quite an astonishing omission. This is one area where plain Java is actually better than Kotlin.

internal visibility is basically the same as public, which makes it pretty useless, unless you want to divide your app into lots of tiny Gradle projects.


#11

Couldn’t agree more.

I think internal has its best use cases for libraries, or large projects that are modularized. Package should cover projects that aren’t modularized. Would make life much easier.

While we’re at it, is there any way to implement file level visibility?

// file.kt

class Foo private constructor(i: Int) {}

class Bar {
  fun baz() = Foo(0)
}

Why there is no package visibility modifier?
#12

All private top-level classes, functions and properties have file-level visibility.


#13

In my example, Bar can’t access Foo's private constructor. At least Android Studio tells me it can’t.

I don’t want it to be internal because then my whole app can see it.

I technically don’t want it to be package (although that would be an acceptable alternative)

I do only want this file to be able to access it, even from outside the class. That’s what I meant by file-level visibility.


#14

I think internal has its best use cases for libraries, or large projects that are modularized. Package should cover projects that aren’t modularized. Would make life much easier.

Then your project should be modularized.
If you want to “cover projects that aren’t modularized” then you should have sticked to Java, when such bad practices are not actively discouraged. Switch to Kotlin only when you’re ready to write maintainable code.


#15

How am I supposed to do unit / whitebox testing properly?

Via public methods. Even unit tests should not depend on the internal decomposition. You should be able to refactor private methods without the need to change the unit tests.


#16

A. Modules wouldn’t fix the"file level" visibility issue I described. Unless you’re suggesting I replace every package with a module in which case:

B. By splitting my project into just 2 modules, my build times went up by 1.5x. 3 modules caused it to go up 2.3x. That’s just not acceptable for me, and I shouldn’t have to lose out on a core language feature because of it.

C. Cyclic dependencies are an issue. Which means I’d have to further subdivide certain packages to break them. Which means more modules. Which means longer build times.


#17

I very strongly agree with the arguments that @vach, @norswap and @kirill_rakhman have made here for a stronger tool than simply internal.

@yole One can obviously understand the idealist motivations that you state regarding package-private being an imperfect protection scheme. The problem is not with Kotlin’s lofty rationale. Instead what you are seeing expressed in this thread is the very practical frustration over the lack of a replacement solution in Kotlin.

Instead of the two more user-acceptable options of either
A) retaining Java 6’s horribly lousy visibility vocabulary, or
B) architecting and providing a superior system than Java’s;
Kotlin punted on the issue provides neither.

Again, it’s understandable for JetBrains to have considered the stance that it took when designing Kotlin (ie. it’s understandable that when given the chance to create a clean new language, one would rather everything be squeaky perfect, and that time might not have been available to come up with a better way just yet; and that maybe it wasn’t predicted to hurt JetBrains’ own typical usage patterns and thus not a high priority; and maybe even that Project Jigsaw was already known of and it was thought that Kotlin could wait for it; and not to mention any potential private goals of eclipsing the JVM altogether). However, as the legitimate and common examples listed in multiple people’s posts here illustrate, this IS a painful part of working in Kotlin for many developers who aren’t JetBrains (at the very least), and an expressed recognition of this issue — at the least — could go a very long way.


#18

My additional argument to add as to why this deficiency is so notably painful, though, is that large Kotlin files in particular get extremely laggy within IntelliJ IDEA. That makes this situation altogether very unfortunate.


#19

Wouldn’t then **internal-**package-private visibility be a possible solution that you guys would be willing to accept/tolerate/implement?


#20

Since my comments here, i’ve been coding in kotlin for quite some time, and honestly if you have files so large that intellij lags there is a code smell maybe you need to revisit that code… not a node js after all :smiley:

Imho not having these package private is not that big of a deal, but as it would allow complete backward compatibility it made more sense to me that we had it… I struggled when i was initially converting my code to kotlin… but now its just joy and happiness :smiley:


#21

True. But having few related to group in one kotlin file makes sense to me. It makes more elegant, in fact. I am trying to convert a java project to Kotlin. I get to see very few files in kotlin because of reduced code and related classes in one file. You could argue that we can create inner classes in java. But i feel its more relaxed and not bound with any scope rules except if we have to restrict file level visibility.


#22

It seems to me that a lot of use cases where people ask for package private accessibility what they want/need is actually friend declarations (give access to a much smaller set of types. None of the use cases needs package that is broader than internal (which Java’s package accessibility actually is).

File private (which is provided by Kotlin) covers most of the friend needs. For those methods that are “safe” but should not be part of the API internal visibility works well. For those methods that are not safe if not used carefully, you want all code that manipulates that to be in the same file and certainly not visible to random other files/classes in the same module. That only really leaves the testing of these unsafe methods. This is not really any other problem than testing private methods in general with the exception that now private can be multiple types that live in the same file.


#23

You are right. The idea of internal looks good to me and i liked it. But on the other hand, package modifier is meant to be visible within the same package. Outside the module, if i can create the same package, i should be able to access the class that is package protected. That is what Package visibility modifier meant to be.

I want to state that it provides one level of protection within the same package. Internal is broader above the package visibility.


#24

Internal really is stricter than package visibility. That is, unless you go the way of sealed packages where external classes are not allowed to be in the sealed package. In that sense it is like internal, but a bit stricter as it limits to the same package. The big problem in that case (besides the fact that most don’t seal classes) is that a package is a very broad scope to give access to. Generally much more than needed. Looking at it, it is generally used as a way to allow tests to get at the guts of the tested class. Whether that is a good idea is one question, but in that case, package is a horrible solution for it, and in many way internal is better as it at least doesn’t let the symbol escape the module (and therefore become part of the API/ABI which package visibility does when not using sealed packages).


#25

What’s the right way to do blackbox (not whitebox) testing?

In Java I could have a few classes in the same package that can interact with each other in non-public ways using package-protected members. I can then have my tests in a different package, so I can test the public API and only the public API.

In Kotlin, because my tests see the internal members it’s easy to accidentally create tests that rely on internal functionality. The only alternative seems to be to place all of my non-test code in a single source file and use private in place of internal. This still doesn’t help for methods/properties, as making them private hides them even from things in the same source file.