I'm trying Kotlin and want to implement a lazy extension property for Activity:
/**
* Activity module
*/
val Activity.activityModule: ActivityModule by lazy {
ActivityModule(this)
}
The compiler errors with:
'this' is not defined in this context
How can I qualify this as Activity this? I have read a guide but can't get it. this@Activity
says the reference is unresolved.
Other answers here have pointed out that it is impossible to reference this
within the stdlib's current implementation of the lazy
receiver, and that one could implement their own delegate. So I decided to implement it and post it here...:
class LazyWithReceiver<This,Return>(val initializer:This.()->Return)
{
private val values = WeakHashMap<This,Return>()
@Suppress("UNCHECKED_CAST")
operator fun getValue(thisRef:Any,property:KProperty<*>):Return = synchronized(values)
{
thisRef as This
return values.getOrPut(thisRef) {thisRef.initializer()}
}
}
Here is some code showing how to use it.
This implementation uses a weak hash map to store a separate value for each receiver...this comes with a couple of implications...:
distinct instances that are structurally equal will share the same value.
in some cases, values that have already been initialized for some receiver could be garbage collected which means that the initializer might be called again to re-initialize the value if it is accessed again.
lazy
calls initializer
function when it is accessed first time and then stores the value returned by the initializer
to return that value on successive accesses.
An instance of Lazy
is capable of storing exactly one value. When you delegate extension property to a Lazy
instance, you're getting a single instance of Lazy
serving getValue
requests from all instances of the receiver type, in your case it's Activity
. This results in Lazy
computing value only for first Activity
and using that value on all subsequent calls for other instances of Activity
.
Therefore while it's syntactically possible to pass an Activity
to initializer as a receiver and refer it as this
inside as @voddan suggests in this answer, the Lazy
itself is not capable of storing different value for different receivers.
An ability to have an external storage for extension properties may likely be covered by "Attached properties" feature KT-7210.
I don't think Lazy
should have this ability as it complicates significantly its implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With