@pdvrieze - " A common use for package visibility is to provide access for testing. "
Hmm I am not sure
Suppose that I have a module: article
In my module I have a three packages:
application
domain
infrastructure
In the Java project (Java 9+) I can have a public facade, interfaces, dtos in a application package also i can have a public interfaces and aggregate class in a domain package and finally all classes in infrastructure which implements those interfaces have package scope visibility. (Others classes in infra have package scope visibility)
So any class from application/domain package canāt call infrastructure impl details directly.
My module can expose only a facade class and dtos classes (jigsaw).
Can you give me the example how it could work in Kotlin (with the same package structure)
Beyond the question whether those should be separate modules, you can use two options:
Take advantage that a private (top-level) class is accessible to code within that file (file private instead of package private).
Create 3 annotations: @Application, @Domain and @Infrastructure. Then annotate the implementations with those annotations. Then you can check that these annotations (or eg. ā@OptIn(Application::class)ā) are not used where they should not
āNeverā is a strong word. I think itās safe to say that package-private scope is not currently plannedāThat doesnāt mean that it wonāt happen sometime in the future.
As @pdvrieze explains, you can get this kind of scoping now in Kotlin using modules. A second option is to restructure your internal pseudo modules into file-private scopes. Or you could try using OptIn annotations and help evaluate if they may be a superior alternative.
It does seem that a more flexible, internal-to-a-module scoping control is what you want. And yes, package-private does provide a better means for this internal-to-a-module scoping than file-private and protected in a lot of cases.
Since it seems that a lot of the use cases are either A) inject test code into a scope via placing it under the same package, or B) creating a pseudo module based on a package name, I wonder if the correct questions to ask would instead be the following:
Can we have an additional scope control mechanism to refine our scopes within a single module? Unlike the internal vs external controls, more fine-grained controls will help organize code.
Can this additional scope control allow for composition without class hierarchy or location restrictions? The current options force you to either place your code inside a specific location (file-private) or subclass (protected). The additional control could also not force you to place your code into a specific folder/package (package).
The package visibility scope does provide this kind of more flexible scope control --albeit, in an arbitrary way. In an alternative history, Java could have made scoping based on a class or filename name prefix instead of package pathāmaybe call it prefix scope⦠Glad it wasnāt done that way
A lot has changed since Javaās package-private scope was decided on. A part of me wonders if Java would have ever added package-private scope had the module system come first.
IMHO Instead of asking for the same old visibility controls, itās worth pitting the old package-private against other solutions that also solve these questions and see which one comes out ahead.
EDIT: Iām surprised I havenāt seen any requests for allowing protected on top-level declarations. This would allow for package-private scoping in almost the same way package would.
The structure of the packages should represents my architecture.
I dont think that create a separate maven module for instance - a application with only one class is a good idea - for me is over engineeringā¦
āWhat we usually consider as impossible are simply engineering problems⦠thereās no law of physics preventing them.ā
In Kotlin and the JVM protected has a different meaning than in the Java language. It means onky accessible by children. Even if you consider that the file scope introduces a class (which is a JVM implementation detail) it can not be inherited.
Today I had a training on Kotlin programming language, many people were of the same opinion that the lack of package scope is a significant limitationā¦
For this reason, I cannot design my solutions the way I would likeā¦
This topic is now 109 posts long and I believe it should be considered as a mega-topic risk.
Despite there bring some new talking points (OptIn alternative), I suspect this topic is too long to support valuable discussion. Newer ideas like OptIn scopes can be discussed better elsewhere where the topic is not flooded with positioning for/against package-private by new readers.
This topic receives a lot of traffic and itās a hotspot for those coming from Java to post their position without adding anything new. The longer this post means itās not practical for new readers to go over whatās already been discussed.
There may be more discussion to have here in the future so itās hard to say it should be closed. Ideally those new discussions would be able to start fresh and focused instead of carrying the baggage of this topic.
Long thread. A lot of arguments and the counter argument is security and create multiple modules.
The security concern is not really 100% valid, because it can be broken using internal modifier as well. Using modules is valid, and we do use it, but sometimes you donāt want to create one module for 5 classes.
The other option provided is put all your classes in one file, but having multiple classes in one file makes it hard to work in a team where people modify the same file but different classes.
We are not asking to replace internal modifier. We are asking to have another modifier that includes internal modifier functionality along with the package visibility restriction. Why? To be able to split larger files, to have a service that internally calls mini-services to do its work and have simpler unit tests without exposing it to other packages, to help new developers in the team understand the contracts of exposed APIs, to help IDE āunderstandā I donāt want to be suggested about some classes in a package that should not be used outside of it, to have options. I simply donāt understand all the negativity to put a feature requested by years that would be used by developers.
We all are developers, we all aim to be professional and the idea of not adding a feature because it can lead to bad practices, well, anyone can do bad practices even with all the restrictions in the world.
At the end, why donāt add the feature as experimental and warn or error if it is used without explicitly declaring in the project settings that the developers want to use it. That way all the companies and projects in the world wonāt need to use it and can be sure that its developers are not using it since it is not enabled, while the rest can work with it.
5 years since this thread started, a lot of traffic, way to many arguments without additional counter-arguments, why not add it as experimental and let the people try it. If it doesnāt work or the people says it is wrong, then remove it.
From my perspective the usage of the optin system with custom annotations can replace most of the use cases where you would otherwise use the (in many ways still too broad) package visibility. As I see it, package visibility is a replacement for the ability to have friend classes/methods. Optins can basically provide that (except the declaration is at the use site not the declaration site - something that can be better within a single module where you can statically check violations).
I think you are both right. They can be extended in the very same package. Sub packages are not allowed. But only in the same module.
Sealed classes can now have subclasses in all files of the same compilation unit and the same package. Previously, all subclasses had to appear in the same file.
+1 to modifier for package visibility (including sub packages of course)
Thatās something like internal + package private, which I think is better than javaās one for securiy reason.
Also this implementation is too heavy to use since it required a subclass to access package private attrs.
But at least we finally have a real package private thing in kotlin, I think the complete feature will come soon
Iād vote having package visibility. I encounter a feeling ādamn, no package-private modifierā over and over again.
My current workaround is to create an impl or internal sub-packages everywhere (commonly used convention).
But the only red flag a developer has is import some.stuff.impl statement at the top of a file which is usually is folded and looked-over during code reviews. So, definitely not perfect. A ktLint rule for disallowing access to .impl package outside some.stuff would be great as an addition to this workaround.
But still, this is just a workaround. package-private visibility modifier is a must and security/encapsulation argument has nothing to do with it. Itās also useful in unit testing of pure functions which contain some complicated logic. I usually end up with having public global functions just for the sake of testing. Or
private fun someComputation(...) = ...
fun someComputationForTesting(...) = someComputation(...)
Terrible, terrible workaround. Replacing unit tests with quazi-integration tests with a carefully crafted data to test edge cases of one of many internal funs which will be executed⦠is even worse IMHO
However there is a something I didnāt like in JAVAs package-private and could be improved in kotlin.
Whenever a module increased in complexity and needed to be subdivided into subpackages, all package-private had to be thrown out of the window.
First design
public some.foo.FooService
pkg-private some.foo.ImplDetail1
pkg-private some.foo.ImplDetail2
some time later:
public some.foo.FooService
public some.foo.detail1.ImplDetail1 // needs to be public now
public some.foo.detail2.ImplDetail2
Ideally what Iād like to have is a modifier which makes a thing visible in itās package and all subpackages.
Without package level visibility modifier, encapsulation code will be difficult. I agree that the file level private modifier is useful, but we canāt write all code in one file. On the other hands, split code to more and more module is unacceptable because of the build system.(That might be a choice if the build system can be improved. The cycling dependencies also should be considered.)
Iām neutral towards introducing package protected visibility. But Iām strictly against the solution to simply add a new visibility modifier (pkg-private or sorts). Instead I hope for a structured and uniform way to handle such things in the future. I have written down a proposal.
It can be used in a basic mode where it is extremely simple: There is just private (and protected as special case) but at more locations than currently possible. In the advanced mode, it is maximally flexible: Any visibility constellations can be realized. But the different layers/levels in the source code are treated similarly with respect to visibility.