First of all, delegation in kotlin is awesome. I haven’t written a huge amount of kotlin, yet I ran into the following frustrating limitations multiple times already.
Unlike with delegated properties, the delegate expression for interfaces can’t refer to this
, despite the delegate having to be stored in a (n invisible) field on this
Consider the following code:
// not using var here intentionally, to separate the getter and setter implementations.
interface PlotData {
fun getOwner(): UUID
fun setOwner(owner: UUID): Boolean // returns true if there's a change
}
interface Database {
fun setOwner(plot: Plot, owner: UUID)
}
/**
* Overrides mutating methods from PlotData
* to update the database if there are changes
*
* Note: Any data associated with a plot is referenced though the data field
* This field can be reassigned, such that a plot is effectively copied to another location
*/
class Plot(var data: PlotData,
private val database: Database) :
PlotData by data {
override fun setOwner(owner: UUID): Boolean {
if (data.setOwner(owner)) {
database.setOwner(this, owner)
return true
}
return false
}
}
If you decide to decompile this code, you should notice the following:
Delegated methods from PlotData
refer to final field called $$delegate_0
or something like that.
The mutable data
field still exists, and is referred to by explicitly implemented setOwner
method.
This means that calls to setOwner
and getOwner
will refer to other instances of PlotData
if you reassign data
to another instance. This is a bit counter-intuitive when using the short constructor syntax of added var
in front of the data
parameter in the constructor. You might think you’re referring to the data field, but really, you’re just giving it an expression to evaluate: the constructor parameter itself, not the field.
There are 2 limitations that make it impossible in the current design of the language to refer to the same field:
- Delegate expressions are evaluated once and then cached in an invisible field
- You can’t refer to
this
in the delegate expression
If the compiler could somehow derive that I want it to refer to a specific property, that would make the feature so much more usable for me. You also can’t make it compute the delegate lazily, which you could by referring to a specific delegated field (which would be backed by another field indirectly)
There are many more cases where the above 2 limitations are a problem.
I can give more examples but I don’t feel that that’s necessary.