In Kotlin, there are the following visibility modifiers:
public (default): the element is visible everywhere.internal: the element is visible within a single module (jar/gradle module, etc.).protected: visible only within the class and its subclasses.private: visible only within the file or class.Features:
private restricts access to the file scope, internal — to the module, while public/protected make no sense outside of a class.private — only within that class, protected — plus subclasses, internal and public — as described above.class MyClass { private val secret = "hidden" protected val id = 42 internal fun foo() {} public fun bar() {} } internal fun moduleFunc() {} private fun fileOnlyFunc() {}
"Can a top-level function be protected? If yes — how does it work? If no — why?"
Answer: No, a top-level function cannot be protected because there is no class it belongs to for that access level. The compiler enforces this — a compilation error will occur.
protected fun magic() {} // Error: protected modifier is not allowed for top-level functions
Story
In a fintech app, it was forgotten that the internal modifier grants access to all elements of a module. As a result, when refactoring, part of the logic was moved to another gradle module, causing data access to stop working, but developers did not notice it immediately, as there were no compilation errors in the old tests.
Story
In a multiplatform project, confidential data was defined as private properties in a companion object. It turned out that this data is serialized and becomes accessible via reflection, because they were declared as val without using annotations to limit export.
Story
At the start of a mobile project, private was used for top-level functions, thinking this would limit access to partner classes. However, in the shared file with utils, these functions were visible to everyone, which led to a risk of information leakage and unforeseen use in business logic.