ProgrammingBackend Developer

What are visibility modifiers in Kotlin and how do they affect encapsulation and application architecture?

Pass interviews with Hintsage AI assistant

Answer.

History of the question:

Visibility modifiers are a key feature of Kotlin, inherited and improved compared to Java. They allow you to restrict access to classes, functions, and properties, supporting better practices of encapsulation and modularity.

Problem:

Incorrect use of visibility can lead to violations of architectural layers, leakage of implementation outward, or vice versa — making classes and methods inaccessible where they are needed. Errors in this are often discovered too late.

Solution:

Kotlin has four visibility modifiers:

  • public — accessible everywhere (default)
  • internal — accessible only within a single module
  • protected — accessible within a class and its subclasses
  • private — accessible only within a file, class, or object

Code example:

open class Base { private fun onlyBase() {} protected fun baseAndDerived() {} internal fun insideModule() {} public fun anyone() {} } class Derived : Base() { fun test() { baseAndDerived() // accessible // onlyBase() — error } }

Key features:

  • internal is specific to Kotlin, absent in Java
  • Modifiers for top-level elements work differently: private restricts visibility by file
  • In interfaces, all methods and properties are public by default

Trick questions.

How does the internal modifier work when publishing a library?

internal hides elements within a single module, but if you compile the library into a jar/aar, internal elements are visible through reflection.

What is the difference between private for a class property and a top-level function?

private on a class property restricts visibility to the class itself, while for top-level, it restricts visibility to the file where the element is declared.

Can you apply protected to a top-level function?

No, protected is only allowed for members of a class or interface. It cannot be used for top-level — there will be a compilation error.

Typical errors and anti-patterns

  • Overly open classes and functions (public without necessity)
  • Using internal where the module combines independent components
  • Attempting to use protected for top-level functions or properties

Real-life example

Negative case

A large library declared almost all APIs as public, including utilities and helpers — as a result, users became dependent on implementation details.

Pros:

  • Ease of use for everyone

Cons:

  • Difficulties with backward compatibility and refactoring

Positive case

Only necessary classes declared as public, others internal or private, visibility levels distinctly separated.

Pros:

  • Controlled access, easy internal changes

Cons:

  • Requires adherence to architecture guides and careful design attention