Search code examples
multiple-inheritancedelegationkotlin

Partial class delegation in Kotlin


How do I partial delegate methods/fields in Kotlin?

To be specific: here I am trying to inherit class User from interface TraitA and implement field marked: Boolean in the wrapper StateA. That would clean up the User implementation, because marked is just a state field. Note that TraitA can't be a class because I want to use several such interfaces: User() : TraitA by StateA, TraitB by StateB, ..

/* does not compile (Kotlin M12) */
interface TraitA {
    var marked: Boolean

    fun doStaffWithMarked()  // must be overridable
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA(){
    override fum doStaffWithMarked() {
        //...all fancy logic here...
    }
}

The alternative is to implement all in one place:

class User() : TraitA{
    override var marked = false // ugly code

    override fum doStaffWithMarked() {
        //...
    }
}

Is there a way/pattern that would solve that problem with easy and as little code as possible? Code/bytecode generation is not an option for me.

UPDATE

I was not very clear about that, but please note that doStaffWithMarked() is unique for every User.

So I may suggest a 'half-bad' solution with run-time assertions:

interface TraitA {
    var marked: Boolean

    /* must be overridden */
    fun doStaffWithMarked() = throw UnsupportedOperationException()
}

class StateA() : TraitA {
    override var marked = false
}

class User() : TraitA by StateA() {
    override fum doStaffWithMarked() {
        //...all fancy logic here...
    }
}

The question is still open, since a really good solution would check that doStaffWithMarked() at compilation time.


Solution

  • Split up TraitA into two interfaces, then delegate the one and implement the other:

    interface TraitA {
        var marked: Boolean
    }
    
    interface TraitAPlus : TraitA {
        fun isMarked(): Boolean
    }
    
    class StateA() : TraitA {
        override var marked = false
    }
    
    class User() : TraitA by StateA(), TraitAPlus {
        override fun isMarked(): Boolean {
            return marked
        }
    }