Kotlin to support package protected visibility


#1

In java package protected access was very handy, because it allowed to write modular code, for example you could have a complex independent component made of 10 classes only one of which had public access and would expose the necessary interfaces for that functionality, while keeping other 9 completely isolated within the project. Not all projects are small enough to rely on “internal” to hide stuff from outside world. Most of the time to keep the project itself modular you want this package confinement. Then you might separate some of it to different small project.

This is not possible with kotlin unless you stick all those classes into one file and put private on all of them…

Another problem is that you cannot test any method/class that is not public. Naturally it might be exactly what one needs to do, but some classes that will expose just few methods will have very very poor test coverage… Imagine you have this file with several classes in it, the public class exposes few methods that will provide the functionality. You wont be able to test anything except those few methods. Basically test does not have any more visibility than any other code.

Please someone explain the motivation behind not having package protected access…

May i suggest to have it in future?


#2

The motivation for not having package protected access is very simple: it does not provide any real encapsulation. Any other module in the system can define classes in the same package as your complex independent component and get full access to its internals. On the other hand, classes with internal visibility cannot be accessed from any module other than the one where they are defined.

And you definitely can test methods/classes that have internal access: the tests of a module have full access to internal declarations of that module.


#3

I’m in favour of package-protection as well.

Yes, the protection is not enforceable. But I don’t care too much about that.

I want to have a some functionality spread over multiple files, where I can make explicit what the public API is. If someone wants to use the private API, fine. But at least it’s clear what is public, and users (and even myself!) are prevented from accidentally using internal things. Currently, this can only be achieved by cramming everything in the same file, or using modules, which are way too heavyweight for what I want to use them for.


#4

Also with package protected visibility you use whatever names you want, and those won’t pop up every time when on the other end of the project you autocomlete a class name…

These are very little arguments but what I like about this language is that it sort of extends Java, but in this case it restricts and tells it’s rules, and the motivation behind that looks pretty subjective, let devs decide which way they like things. I still find it ugly to put a lot of stuff in one file. All other decisions I know about are very reasonable and I’m happy with those being enforced, those are best practices.

But my inner javist is fighting this one.


#5

I’m in favor of adding support for package private visibility and I second all the previously mentioned arguments in favor of it.

Regarding @yole’s comment: Internal visibility isn’t strictly enforced, too. It’s compiled to public and mangled, but it can still be accessed from Java. Private members can be accessed too using reflection.

In my opinion it’s not about whether you can enforce a visibility rule 100% from a technical standpoint but about what the enforcement gives you and the users of your API. In the case of package private, the enforcement is too weak to prevent your users from breaking it (even without reflection) but it’s good enough to prevent the members from popping up in the completion list. Especially, when I’m the one consuming my own API (within the same module), I would be very glad to be able to hide the implementation details from the completion list while still being able to organize my code properly within the package.


#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: