It is often a concern to avoid memory leaks in scenarios where a child object takes a lambda as handler that strongly references the parent object, creating a cyclic reference unless the lambda body uses a weak reference to the parent object. For instance, consider the following minimal example:
class Example {
val weakThis = WeakReference(this)
val widget = Widget(0, 0) { x -> weakThis.get()?.action(x) }
fun action(x: Any) {}
}
If we used this.
instead of weakThis.get()?.
, or the method reference this::action
, the instances of Example would never be collected by the GC, since their widget
properties would hold cyclic references to them.
I think the language would benefit from a simple and straightforward syntax to use weak references within lambdas.
My first idea was giving a meaning to the expression this?.
, since this
can never be null, to create a weak reference when constructing the lambda, and use it if still accessible when executing the lambda. This would simplify the previous example to:
class Example {
val widget = Widget(0, 0) { x -> this?.action(x) }
fun action(x: Any) {}
}
Of course, using a weak reference in a lambda would force it to not be inlined, since the weak reference must be stored somewhere.
For complex lambdas, using this?.apply
to enclose the optional parts of the body could become a frequent construct that could easily wrap existing code (an inspection could automatically wrap lambdas like this).
For simple method reference lambdas, like the example above, perhaps the syntax could be extended as well for something like this?::action
, although I’ve noticed the IDE warns about this syntax being reserved for future releases, so something different may be planned for it.
In regards of actually omitting the this
keyword in these kind of references and allowing to simply use ?.
, I feel it would only lead to confusing code and also syntax ambiguity when semicolons are omitted.
However, I can see how the this?.
idea could be considered confusing, since it uses the null-safety construct ?.
for something unrelated with nullity, so another possibility would be assigning a new symbol operator for this purpose, such as :
(for example, I’m not sure of the conflicts this choice would have with other language features).
Using a new symbol operator would have the benefit of extending the syntactic sugar to weak references of other objects than this
, though I don’t think these use-cases are as relevant.
Outside of lambda declarations, I don’t think this syntax should have any meaning, since the only problem it addresses is the type of reference that is created within the lambda object.
Currently, I’m not aware of a simpler way to create these weak referencing lambdas than the first example, neither from the receiver side, since the method that takes a lambda cannot change its references, nor from the caller side without having a weak reference to use within the lambda body, that needs to be declared somewhere else, breaking the flow of the code.
Personally, I think that giving this?.
a meaning would be an elegant solution, but I can only speak for myself. On the other side, picking a new symbol operator is always a hard task, which I doubt would ever succeed without controversy. I understand that, since there is already a way to solve the problem at hand, a new feature changing the syntax may not be deemed worth the effort.
Another benefit of having an idiomatic way to create these weak-referencing lambdas is that language users would be encouraged to prevent this frequent type of memory leaks. Perhaps the IDE could also offer a new inspection, suggesting to replace a strong reference inside a lambda for a weak one when a cyclic reference is detected, or wrap an entire lambda using this?.apply
.