Let’s start with the syntax that I would like then the why and how I would use it. Here goes:
WHAT?
interface X {
val l: String
val m: String
data class Dto by X
}
which would be the equivalent of:
interface X {
val l: String
val m: String
data class Dto(override val l: String, override val m: String): X {
constructor(source: X): this(source.l, source.m)
}
}
WHY?
To take advantage of Kotlin’s by
I must use interfaces. I find this pattern works very well but it seems like we could get rid of some more boilerplate. Interfaces are wonderful for proxying but DTOs are pretty swell too. I want the best of both.
HOW WOULD I USE IT?
This let’s me take any implementation of X and pass it to my alternate constructor. Here is a more complete example of what I often do:
interface X {
val l: String
val m: String
data class Dto(override val l: String, override val m: String): X {
constructor(source: X): this(source.l, source.m)
}
}
interface Y {
val n: String
val o: String
data class Dto(override val n: String, override val o: String): Y {
constructor(source: Y): this(source.n, source.o)
}
}
interface Z {
val l: String
val m2: String //This is an example of +/- of a field
val n: String
val o: String
data class Dto(override val l: String, override val m2: String, override val n: String, override val o: String): Z {
constructor(source: Z): this(source.l, source.m2, source.n, source.o)
}
}
class Zebra(val x: X, val y: Y): X by x, Y by y, Z {
//We can lazy load
override val m2 get() = m + "2"
}
val x = X.Dto("Lenny", "Mark")
val y = object: Y {
override val n: String
get() = "Nancy"
override val o = "Oprah"
}
val zebra = Z.Dto(Zebra(x, y))