Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin var lazy init

I want to do a lazy initialization for a var property. Since by lazy is restricted only to val properties I have to write something like this:

    private var currentContextProvider: ContextProvider? = null
        get() {
            if (field == null) {
                field = DefaultContextProvider()
            }
            return field
        }

And now I have to deal with those pointless nullability-aware calls: currentContextProvider?.getContext() or alternatively currentContextProvider!!.getContext()

Am I doing something wrong?

like image 371
Nikolay Kulachenko Avatar asked Dec 22 '17 21:12

Nikolay Kulachenko


1 Answers

Instead of making it nullable, you can decide to initialise it with some default value, which on first access will be replaced with the lazily calculated value:

private val noInit = "noinit"
var currentContextProvider: String = noInit
        get() = if (field == noInit) {
            synchronized(this) {
                return if (field == noInit) "lazyinit" else field
            }
        } else field

(I've replaced the ContextProvider with String)

Custom Delegate

The following implements a custom delegate reusing the former solution. It can be used just like lazy() by defining var currentContextProvider: ContextProvider by LazyMutable { DefaultContextProvider() }

class LazyMutable<T>(val initializer: () -> T) : ReadWriteProperty<Any?, T> {
    private object UNINITIALIZED_VALUE
    private var prop: Any? = UNINITIALIZED_VALUE

    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return if (prop == UNINITIALIZED_VALUE) {
            synchronized(this) {
               return if (prop == UNINITIALIZED_VALUE) initializer().also { prop = it } else prop as T
            }
        } else prop as T
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        synchronized(this) {
            prop = value
        }
    }
}
like image 110
s1m0nw1 Avatar answered Sep 24 '22 06:09

s1m0nw1