Kotlin to support package protected visibility

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.

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.

1 Like

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).

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.

You can put your test source in a separate module, and not in the test source root of the same module. Then it won’t have access to internal declarations of the code under test.

Also note that in gradle each source set is compiled as a separate module and its internals should not be visible in other modules (source sets). The only exception of this rule is test source sets which can see internals of their corresponding production source sets.

The only exception of this rule is test source sets which can see internals of their corresponding production source sets.

I did not know this was specific to Gradle. Does IntelliJ merge sources from different sets based on package?

Another in favor of the current internal implementation - module visibility. I agree it provides better encapsulation than java’s package level visibility. +1

2 Likes

Anyone wants the package private also to be visible to sub packages? i.e. package-private com.bennyhuo.SomeInterface is also visible to com.bennyhuo.impl.SomeImpl ?

7 Likes

Blackbox testing should not be concerned with any details of how the public API is implemented. It is only concerned with testing the behaviour inferrable from the publically visible information.

Whitebox testing is using your knowledge of implementation details to make calls to the public API that triggers certain behaviour of the implementation.

For example, if you have a sort method, you can test it using unsorted data (blackbox testing). If you know it is implemented using quicksort, you can add test cases that cover the different boundary cases for splitting the data into sortable partitions, explicitly testing that boundary checking logic (whitebox testing).

Likewise, if you have a public API that is returning an interface, blackbox testing will only assume that there is one implementation of that, as you don’t know if there are more than one implementation. With whitebox testing, you can see where other implementations are returned, and call the public API to ensure that you are covering those different implementations in your tests.

In your case: what calls do you need to make to the public API to have the package-protected members called? What effects does that have on information accessible to the public API?

Hi,
I suppose that also the performance of the Idea IDE is affected by having all the classes (with “package” visibility) in the one file.
Supposedly I have 5 files with 200 lines of code each. Idea performs very well when I open only one of them.
But in case of all those classes in on single file (1.000 lines of code) I am highly in doubt Idea performance is not affected. Think about having 10 classes or more…

Moreover in terms of distraction avoidance. For me is easier to focus only on one or max 2 things at a time. This means it is easier for me to have only one or two classes open. On the other hand scanning the entire 5 classes kotlin file is against distraction avoidance.

I really think package visibility is very useful. My current case is implementing a DSL over POI apache library. For the client of the DSL the API is very small, but the internals of the DSL is significantly large and I don’t want the client to be offered with it the autocomplete. The 1st client of the DSL is the project the DSL resides on.

Kind regards.

Tony

5 Likes

Hi,

Is there any chance to rethink this decision and, hopefully, have package visibility in kt 1.2.x?
Frankly whenever I have to isolate some classes internals in the same package I really misses the way scala does this (private[model] def doX {}). Of course scala is more powerful in this matter, but for me, package visibility would be a nice addition to kotlin.
Apart from this, I really enjoy developing with kotlin.

Thank you.

Hi, I created account only to comment and say: You are wrong. Guys who developed JAVA language has great Idea to make package scope as a default scope (without keyword). Some devs has hard time to understand of true potential of Package scope and even if I explain to You you will probably not get it. But I will try :smiley: I have one small application with rules:

  1. app has 3 modules/packages: user management, product management, shop
  2. user module does not see any class of product module because it doesn’t need to.
  3. product module does not see any interiors of user module because doesn’t need to.
  4. shop module use published iterfaces/facades (public class (only one per module and dtos) ) of user and product module and do not see their interiors because it doesn’t need to.

the whole code is encapsulated on each package levels.

If my junior dev colleague will change something in product module/package I’m sure that he will not break whole application and what’s more important I have better control of dependencies between modules.

It’s architected that way because each module can be moved to micro-services in future or moved “somewhere” (we do not know that yet) and it is easy because they all has only one point of access for each module (even Controller class is package scope).

Using “internal” I would have to create always 2 modules for dto’s and for service for each module/package
and there would be additional configuration on my head.

It would be great assets to developers if it would be default scope.

There is great presentation of this and package scope: JDD 2017: Keep IT clean: mid-sized building blocks and hexagonal architecture (Jakub Nabrdalik) - YouTube

5 Likes

Hi,

I was discussing about this architectural decision on slack channel, and I was told this package visibility is going to be discussed again in one of the coming, say, kotlin architecture meetings.
Probably they will be reconsider their initial decision and add package as a visibility modifier.

The Jetbrains Team has the excellent reputation to listen to their users, and if our request seems to make sense to their architects and decision makers they will certainly implement this.
This responsiveness to the user requests makes, after all, their products top-notch ones.

Kind regards.

9 Likes

Some good arguments have been made for package level encapsulation however, my issue with having only the package keyword and no internal keyword is, package often leads to cluttered packages because a library or application needs/wants to have an internal object shared across packages without exposing it to an outside developer.

An example would sharing a bearer token in a client side library for Android, outside developers shouldn’t see it but if the library supported different feature sets that used that token object then why should the developer be forced to put those different feature sets into a single package and/or expose that token outside of the library?

I wish Oracle would enforce internal encapsulation but I’m actually encouraged that Kotlin added it, so much so I started looking at doing backend development with it and I am watching Kotlin Native closely. If internal went way I would probably start to lose interest in Kotlin because moving on from some common Java pitfalls is important and seeing Kotlin cave to the Java community would signal to me that we will just end up with a slightly less verbose Java without any of the benefits from using a modern language.

I’m not saying don’t add package and it doesn’t have a place. What I’m saying is whatever is decided, the internal keyword should stay.

2 Likes

I agree with you. And also removing the internal keyword would be a breaking change and therefor I am pretty sure that it wont happen. Still I would love to see a package private access modifier added.

9 Likes

A common Dependency Injection pattern is to have a package-private class injected into a public class. The Kotlin file-private option doesn’t work in that case because the DI framework can’t construct the file-private class.

I know about the common construct, that doesn’t mean it is a good idea. The main reason for the package private is to allow access to the test suite. It is a test suite, there is nothing against using a little reflection (and setaccessible) to solve the test suite problem. In the production code you then have holes you don’t need. From my perspective an internal declaration is not really any bigger a hole than a package private declaration, except perhaps slightly in JDK9+ with modules where packages are sealed so clients cannot extend packages (to circumvent package private) and internal does the same thing at earlier api levels.

If you want to do dependency injection, you have something that does the “creation” of the objects. This thing can provide anonymous classes or anything (as long as they implement the correct API) - and perhaps the classes should be private to the injector to prevent clients from using hidden API.

and perhaps the classes should be private to the injector

That would be a radical change and would defeat the purpose of having “friend declaration” code organized together.

This continues to be my main frustration with Kotlin, they took away a simple encapsulation tool and didn’t give us a replacement besides telling us either that encapsulation is useless if it’s not 100% foolproof, or that we need to break everything up into countless, much heavier weight, acyclic-ly dependent little “modules”.

From what I can see, the main problem with internal compare to package private is that internal is tied to Gradle/Maven modules. This discourages developers from building small modules, as doing so affects compilation time and complexity of the overall project structure. Package private solves those problems, but introduces a lot of problems by itself. Instead, I propose that we look for alternative solutions. My suggestion would be to add a notion of modules within the language itself, that are more lightweight than what the build systems offer, but also more flexible than packages, since packages are restricted to a single namespace and a single directory file structure.

4 Likes