Kotlin to support package protected visibility

There are two disadvantages: no Java compatibility; and the ability to opt in at the use site. If you have some related modules (and thus public annotation) it still has abi consequences on a technical level. But as long as sun.misc.Unsafe exists people that want to use unstable api can anyway.

2 Likes

@pdvrieze - " A common use for package visibility is to provide access for testing. "
Hmm I am not sure :wink:

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
1 Like

I can also use Archunit library…
I am still not convinced…

So I am to understand that Kotlin will never support package scope visibility?

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

  1. 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.
  2. 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 :slight_smile: --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 :stuck_out_tongue_winking_eye:

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.

3 Likes

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

  • Michio Kaku

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.

1 Like

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…

2 Likes

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.

Here’s the full explanation of Mega-topics (Please close the mega topics)

3 Likes

arocnies - Yes I agree. This discussion show that developers need a package scope in Kotlin.

6 Likes

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

1 Like

In Kotlin 1.5.0, sealed class can be extended within the same package, maybe we can do something like package private with sealed + protected

Correction: they can be extended within the same module, so it is practically the same level of restriction as internal

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.

https://kotlinlang.org/docs/whatsnew15.html#package-wide-sealed-class-hierarchies

+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

This post was flagged by the community and is temporarily hidden.

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.