Internal mechanisms of Lazy

skydovesJaewoong Eum (skydoves)||6 min read

Internal mechanisms of Lazy

Kotlin provides a very useful delegate: lazy. The lazy function creates a property whose value is computed only on its first access and then cached for all subsequent calls. While the public API is super simple, a deep dive into its internals reveals a well-architected system built on the Lazy interface, with multiple, specialized implementations designed to handle different thread-safety requirements.

The entire lazy mechanism is built around a simple but creative interface. This interface defines the public contract for any object that represents a lazily initialized value.

public interface Lazy<out T> {
    /**
     * Gets the lazily initialized value of the current `Lazy` instance.
     * Once the value was initialized it must not change during the rest of lifetime of this `Lazy` instance.
     */
    public val value: T

    /**
     * Returns `true` if a value for this `Lazy` instance has been already initialized, and `false` otherwise.
     * Once this function has returned `true` it stays `true` for the rest of lifetime of this `Lazy` instance.
     */
    public fun isInitialized(): Boolean
}
  • value: T: This read-only property is the main entry point. The first time it's accessed, it will trigger the execution of the initializer lambda. On all subsequent accesses, it will return the cached result.
  • isInitialized(): Boolean: This function allows a developer to check if the initializer has already run without actually triggering it.

This interface is what enables property delegation. The getValue operator extension function operator fun <T> Lazy<T>.getValue(...) simply delegates the property read to the lazy.value property, as you've seen in the below:

/**
 * An extension to delegate a read-only property of type [T] to an instance of [Lazy].
 *
 * This extension allows to use instances of Lazy for property delegation:
 * `val property: String by lazy { initializer }`
 */
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

This article continues for subscribers

Subscribe to Dove Letter for full access to 40+ deep-dive articles about Android and Kotlin development.

Become a Sponsor