Instead of making it null, you can initialize it with some default value, which at first access will be replaced with a lazy 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 replaced ContextProvider with String )
User delegate
The following implements a user delegate reusing the previous solution. It can be used in the same way as 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 } } }
source share