In Kotlin, visibility modifiers allow control over access to declarations: classes, properties, functions, and top-level (file-level) entities. Unlike Java, where modifiers apply only at the class level, in Kotlin they work for top-level declarations as well, which is important for structuring large projects and library APIs.
In Java, there are no visibility modifiers for functions or properties outside a class—all reside within a public (or package-private) class. Kotlin, however, often structures projects differently, where functions or properties reside not within a class, but directly in a file.
Java developers often expect that public by default works the same way as in Java, but in Kotlin, a top-level function (or property) is visible in all modules unless otherwise marked. Incorrect visibility can lead to lexical cluttering of the public API, unexpected availability of internal utilities, or unavailability of necessary public functions.
Kotlin provides the following modifiers:
Example:
// file: Foo.kt private fun utilityFun() {} internal val bar: Int = 10 public val baz: Int = 20 // public is optional fun printValue() { println(bar) }
Can protected be used for a top-level function?
No, protected is only relevant for members of a class/interface; top-level elements do not support this.
If a top-level function is declared internal, will it be visible in other modules?
No. It will only be visible within the current jar/Gradle module.
What is the difference between a private class and a private top-level function?
Example:
// file: Utils.kt private fun helper() { /* ... */ } // visible only in this file internal fun useful() { /* ... */ } // visible throughout the module
Test utilities declared public end up in the artifact, causing issues for the library client—all that is not related to the public API becomes visible.
Pros:
Cons:
Internal functions are declared private, utilities with internal visibility for common use within the module, only carefully considered interfaces have public access.
Pros:
Cons: