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:
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:
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.
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.