Package protected alternative in Kotlin

VisibilityKotlin

Visibility Problem Overview


In Java, we have the package protected (default) modifier for classes, which allows us to have many classes in a single package but exposes only a few and keeps the logic encapsulated.

With Kotlin this doesn't seem to be the case. If I want a few classes to be visible to each other but no further, I have to use a private modifier which limits visibility to a single file.

So if you want 10 classes in a package but only one of them to be public, you'd have to have one huge file with all the classes in it (and private all over the place).

Is this normal practice or there is a way to achieve some similar modularity in Kotlin?

I don't understand: if they have the notion of a package, why did they get rid of package protected access?

Update: We might have package protected visibility after all
see the discussion here

Update: If you read through the discussion and still think this is a must-have feature for the language, please vote here

Visibility Solutions


Solution 1 - Visibility

Kotlin, compared to Java, seems to rely on packages model to a lesser degree (e.g. directories structure is not bound to packages). Instead, Kotlin offers internal visibility, which is designed for modular project architecture. Using it, you can encapsulate a part of your code inside a separate module.

So, on top level declarations you can use

  • private to restrict visibility to the file
  • internal to restrict visibility to the module

At this point, there is no other option for visibility restriction.

Solution 2 - Visibility

As a workaround for me on android I've created @PackagePrivate annotation and lint checks to control access. Here you can find the project.

Lint checks are obviously not that strict as compiler checks and some setup needed to fail the build on errors. But android studio picks up lint checks automatically and shows error immediately while typing. Unfortunately I don't know a way to exclude annotated members from autocomplete.

Also, as lint is a purely compile-time tool, no checks at runtime performed.

Solution 3 - Visibility

As @hotkeys points out, you can use the internal keyword in a module or you can put all classes that would otherwise belong in a package inside a single file, but sticking several classes in a file may be a questionable design decision.

For me, the package visibility is helpful for its documenting value. I want to know what public interface some package is presenting to the rest of the project, hide factory implementation classes and so on.

So even if it's possible to access package-private classes and methods in Java, I still choose to use the package modifier.

For this I created a project with a single annotation:

package com.mycompany.libraries.kotlinannotations;

import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Documented
@Retention(SOURCE)
@Target({ TYPE, METHOD, CONSTRUCTOR })
/**
 * Use in Kotlin code for documentation purposes. 
 * 
 * Whenever a Kotlin class or method is intended to be accesible at package level only.
 *
 */
public @interface PackagePrivate {

}

Then I can use this annotation in any Kotlin project.

The second step, which I haven't done yet, is creating a PMD rule to enforce this with maven (or any other build tool for that matter) and also be able to see violations of the rule in my IDE with the pmd plugin.

There no is full Kotlin support in pmd at this moment but it seems to be expected at some point.

Solution 4 - Visibility

Package-based protection is pointless in Kotlin because packages themselves are unprotected

In Java, package was tied to directory structure. So if you put your classes in com\example\yoursecretengine, any attempt (deliberate or accidental) to add a rogue class there would be easily noticeable. This is the kind of security we've depended on.

Kotlin removes the ties between directory and package, so I can put my class in "my" directory (eg.src\java\pl\agent_l\illegalaccess) yet declare its package as com.example.yoursecretengine - and gain access to all the properties you've meant as package private.

In fact, a Kotlin project works perfectly without ANY package declarations. This only highlights that packages are "more what you'd call guidelines than actual rules". They're a convenience feature, useful only to unclutter namespace and nothing more.

Relevant quotes from kotlinlang:

> unlike many other languages, Kotlin packages do not require files to have any specific locations w.r.t. itself; the connection between a file and its package is established only via a package header.

And:

> an absence of a package header in a file means it belongs to the special root package.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionvachView Question on Stackoverflow
Solution 1 - VisibilityhotkeyView Answer on Stackoverflow
Solution 2 - VisibilityesentsovView Answer on Stackoverflow
Solution 3 - VisibilityDPMView Answer on Stackoverflow
Solution 4 - VisibilityAgent_LView Answer on Stackoverflow