ProgrammingMiddle Kotlin Developer

How is property delegation implemented in Kotlin? Describe the mechanisms, advantages, limitations, and provide a detailed example.

Pass interviews with Hintsage AI assistant

Answer

Kotlin has built-in support for delegated properties (delegated properties). The by mechanism allows delegating the getter/setter of any property to a specialized object — the delegate. The most well-known delegates are lazy, observable, vetoable, and custom ones.

Advantages:

  • Reusable data ownership logic
  • Easy implementation of patterns like lazy initialization, caching, access control, logging, etc.
  • Cleaner and more declarative code

Example of a custom delegate:

class UpperCaseDelegate { private var value: String = "" operator fun getValue(thisRef: Any?, property: KProperty<*>): String = value operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) { value = newValue.uppercase() } } class Person { var name: String by UpperCaseDelegate() }

Limitations:

  • Delegation works only with class properties (not with top-level variables/properties in objects)
  • Potential issues with serialization (if the delegate contains non-serializable fields)

Trick Question

Can a delegate that requires access to context (e.g., Android Context) be used in properties of companion objects or top-level objects?

Often answered incorrectly with "yes, why not?"

Correct answer: No, because companion objects and top-level objects are initialized before class or application instances, which can lead to errors related to accessing uninitialized context. Delegates requiring access to an instance should only be used in class properties.

Examples of real errors due to lack of knowledge of the topic


Story

Delegation of lazy initialization in Android-ViewModel: A programmer moved a heavy-lazy delegate to a companion object. In some situations (after SDK updates), the application started crashing on initialization — the context was not yet available, but the delegate had already executed its "init".


Story

Incorrect serialization with delegates: A custom delegate was used for data storage, but it contained non-serializable references to context. Errors occurred during serialization attempts, leading to data loss.


Story

Observable delegate with callback error: A developer used Delegates.observable to control state, and inside the lambda, a new value was assigned, leading to infinite recursion and StackOverflowError at runtime.