Home > database >  Property not Overridden when using by keyword in Kotlin
Property not Overridden when using by keyword in Kotlin

Time:10-01

I'm attempting to have two implementations of an interface one of which inherits the default values from the other implementation, but overrides one.

Here's an example that shows the behavior:

fun main() {
    println(Bottom.value) // prints: bottom
    println(Bottom.determineValue()) // prints: middle
}

interface Top {

    val value: String

    val otherValue: String

    fun determineValue() = value
}

object Middle : Top {
    override val value = "middle"
    override val otherValue = "something else"
}

object Bottom : Top by Middle {
    override val value = "bottom"
}

I'm getting unexpected behavior in that, when the property value is used in outside of the Bottom implementation, it returns the value from Middle instead of Bottom.

If someone has more insight on why this is occurring, I'd appreciate any explanation

CodePudding user response:

This is expected behavior that is described in the Kotlin documentation of the delegate functionality.

Note, however, that members overridden in this way do not get called from the members of the delegate object, which can only access its own implementations of the interface members

An implementation being used as a delegate has no knowledge that it is being used as a delegate and therefore cannot and will not access members of that other class. Any of its implementations that call its other members will not use the overridden versions that are in the class that are using it as a delegate. There is no way to get around this problem except to re-implement the feature:

object Bottom : Top by Middle {
    override val value = "bottom"
    override fun determineValue() = value
}

CodePudding user response:

To illustrate Tenfour04's answer:

There are two objects here: Bottom and Middle (both implementing the Top interface).

The call path looks like this:

Bottom.determineValue()
           │ (by delegation)
           │
           └──────────→ Middle.determineValue()
                     ┌─────────────┘  (defined in Top)
                     │
                     └→ Middle.value

Delegation works by forwarding all (non-overridden) calls to the delegate. Here Bottom doesn't override determineValue(), so Bottom.determineValue() calls its delegate, Middle.determineValue(), which returns its own value (because it knows nothing about Bottom).

  • Related