Unneeded limitations of delegated interfaces

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.

2 Likes

I agree completely, unfortunate we are too late… Changing this would mean a breaking change…

So to support the strategy pattern, another syntax is needed.
There are several issues related to this problem, under which 3 are listed here:

(I saw that the strategy-pattern was only half implemented after the kotlin - puzzlers:https://github.com/angryziber/kotlin-puzzlers/blob/master/src/delegates/map/mapped-property-delegate.kts)
By the way, the reason why is chosen for the half strategy pattern:

For the this, you need to give the classes a object, with the this as reference…
The accessed fields/methods can in those cases not be private or protected.
The problem is of course that the interfaces can be used for stand - alone classes…

Having said that, I think the strategy pattern in Kotlin is still easier to write than in Java :slight_smile: