mikesol
mikesol

Reputation: 1197

Kotlin: function delegation

I have a project that depends heavily on delegation and composition in Kotlin. Delegating properties is a breeze, but conceptually I'm not completely sure how to achieve delegation for functions in circumstances where the functions depend on other composed properties. I'd like to do something like this:

interface A {
  val a: String
}
class AImpl: A {
  override val a = "a"
}
interface B {
  val b: String
}
class BImpl: B {
  override val b = "b"
}

interface C<T> where T: A, T: B {
  fun c() : String
}

class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
  override fun c() = ab.a + ab.b
}

// works
class ABC : A by AImpl(), B by BImpl()

// does not work
class ABC : A by AImpl(), B by BImpl(), C<ABC> by CImpl(this)

Of course, this type of thing would be achievable with the following:

interface A {
  val a: String
}
class AImpl: A {
  override val a = "a"
}
interface B {
  val b: String
}
class BImpl: B {
  override val b = "b"
}

interface C<T> where T: A, T: B {
  fun c() : String
}

class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
  override fun c() = ab.a + ab.b
}

class AB : A by AImpl(), B by BImpl()

class ABC(ab: AB = AB(), c: C<AB> = CImpl<AB>(ab)) : A by ab, B by ab, C<AB> by c

but this feels clunky as it requires passing in objects for composition which bloats the size of the constructors - it would be cleaner for me to initialize the objects at the site of the class itself as they have no use outside of the class. Is there an elegant way to this with delegation and/or extensions?

Upvotes: 7

Views: 8792

Answers (2)

mfulton26
mfulton26

Reputation: 31274

You can make C extend A and B instead of passing to it a delegate. e.g.:

interface C : A, B {
    fun c(): String
}

abstract class CImpl() : C {
    abstract override val a: String
    abstract override val b: String
    override fun c(): String = a + b
}

class ABC : A by AImpl(), B by BImpl(), CImpl()

You can also do this with a default implementation in C without a CImpl:

interface C : A, B {
    fun c(): String = a + b
}

class ABC : A by AImpl(), B by BImpl(), C

Upvotes: 7

I don't think this is currently supported very well, but there's an issue that tracks this and related feature requests. (See Peter Niederwieser's comment on the issue.)

Upvotes: 0

Related Questions