Hey there, I'm not exactly getting started with Ko...
# getting-started
s
Hey there, I'm not exactly getting started with Kotlin, but I can't find a general-issue channel regarding Kotlin, so I'll try my luck here! I'm dealing with a situation with inheritance and delegation. Basically, I have a
Logger
interface which includes a
tag
member. I have a
BaseLogger
which provides a default implementation of
Logger
. And I use that class via delegation in other classes:
class OtherClass : Logger by BaseLogger()
. Now I'm running into a problem where the
tag
isn't derived in the way I need it to. Hard to explain- code is in 🧵
Copy code
interface Logger {
    val tag: String?
    fun log(): String? // would usually print to log
}

open class BaseLogger : Logger {
    override val tag: String? = "base"
    override fun log() = tag
}

class B : Logger by BaseLogger() { // delegation
    override val tag = "b"
}

class C : BaseLogger() { // inheritance
    override val tag = "c"
}

@Test
fun t() {
    val b = B()
    val c = C()
    assertThat(b.log()).isEqualTo("b") // fail. actual=base!
    assertThat(c.log()).isEqualTo("c") // ok
}
Here's an example, including a test-case. I want to be able to override
tag
in my classes and use the generalized
log()
function to print message+tag. But as you can see, when I use delegation to implement
Logger
as I do in
class B
, the tag isn't
b
but instead
base
. I understand the reason for it: delegation constructs the delegate first (which has
tag="base"
and applies it to
B
afterwards. But I'm looking for an elegant way around it. I can't do something like
class B : Logger by BaseLogger(tag)
either, because
tag
is still undefined at this point. I could do
class B : Logger by BaseLogger("b")
but that ends up being pretty inconvenient due to the way the code is structured. (This example is simplified.)
h
This is the general issue channel regarding Kotlin! Think of it as "getting started with this Slack" rather than only getting started with Kotlin. 🙂 That being said, your situation is pretty much the same as the example given in the Kotlin docs for delegation, where it says:
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
So yeah, inheritance is probably required here.
s
> Think of it as "getting started with this Slack" rather than only getting started with Kotlin. Gotcha! I'd rather avoid inheritance (composition over inheritance and all that jazz). I've been mulling over it for more than an hour and I'll probably go with something like this:
Copy code
class B : Logger by BaseLogger() {
    val log = createLogger(tag = "b") // uses BaseLogger to construct a logger
}
It's not great, but I can get it to work with DI and tests. 🤷