If you are like me, you've probably used by lazy multiple times before wondering how that works. More recently I've been using by viewModels in Android and I said it's a good time to finally look into this by magic :)

It turns out that it's a Kotlin feature called delegated properties. In summary, whatever expression you set after by , will be delegated the setting and getting for the variable before the by part. This will be done by calling getValue() / setValue() operators.

class Example { var myLazyValue : String by MyOwnLazy() } class MyOwnLazy { private var calculatedValue: String? = null operator fun getValue(thisRef: Any?, property: KProperty<*>): String { if (calculatedValue == null) { calculatedValue = calculateValue() } return calculatedValue!! } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { calculatedValue = value } private fun calculateValue(): String { [...] } }

In this super simple example, I kind of re-implemented a lazy value retriever that calculates the value only the first time that it's accessed. The difference from the standard lazy delegate is that it allows being set as well.

Under the hood, Kotlin will create an instance of MyOwnLazy class and call setValue() / getValue() respectively. Notice that in those operators a property parameter is passed that allows access to the object being delegated (in this case myLazyValue ).

Standard Delegates

For not having to reinvent the wheel, Kotlin comes with some standard delegated properties (some of them are more famous than others). A glance at them, in case you find something that might be useful:

lazy

I think the most famous one. You provide a lambda that is used to calculate the value the first time it's accessed.

val lazyValue: String by lazy { println("This will be called once") "Hello" } fun main() { println(lazyValue) println(lazyValue) }

observable

You provide an initial value and a lambda. Whenever the value is changed, your lambda is called (thus 'observing' the variable). There's another interesting version of this, called vetoable, that allows you to intercept (and potentially stop) the assignment.

var observed = false var max: Int by Delegates.observable(0) { property, oldValue, newValue -> observed = true } println(max) // 0 println("observed is ${observed}") // false max = 10 println(max) // 10 println("observed is ${observed}") // true

map

Allows you to access map values using variables names as key.

class User(val map: Map<String, Any?>) { val name: String by map val age: Int by map } val user = User(mapOf( "name" to "John Doe", "age" to 25 )) println(user.name) // Prints "John Doe". Same as map["name"]. println(user.age) // Prints 25. Same as map["age"].