Tell Kotlin that a generic type is an interface

364 Views Asked by At

Let's say I have a class Foo

class Foo {
    val noProblem = "Hakuna Matata"
}

I now want to decorate it with an ID. Kotlin's delegates make this relatively painless:

class IdentifiableFoo(
    val id: Int,
    foo: Foo,
): Foo by foo

interface Foo {
    val noProblem: String
}
class FooImpl: Foo {
    override val noProblem = "Hakuna Matata"
}

but let's say I have another class Bar that I also want to decorate, and then another Baz, and then another ...

I could just create a IdentifiableXYZ for each of them, of course.

But what I really want is something akin to

class Identifiable<T> (
    val id: Int,
    thing: T
): T by thing

That I could just use for all of them.

And yes, there's a very good chance that the language doesn't support something like that, but the error message made me think:

Only classes and interfaces may serve as supertypes

so can I do some where magic or something to tell Kotlin that T is required to be an interface?

1

There are 1 best solutions below

1
Gowtham K K On

It is not possible in Kotlin. Kotlin only allows super type to be either a class or an interface. Type parameter cannot be a super type of some class or interface.

One workaround might be using a base interface for all the interfaces you are using. But not sure it solves your problem.

class IdentifiableFoo<T : BaseFoo>(
    val id: Int,
    val foo: T,
) : BaseFoo by foo {

    fun doSomething(a: T.() -> String) {
        println(a.invoke(foo))
    }
}


interface Foo0 : BaseFoo {
    val noProblem: String
}

interface Foo1 : BaseFoo {
    val someProblem: String
}

class FooImpl : Foo0 {
    override val noProblem = "Hakuna Matata"
}

class Foo1Impl() : Foo1 {
    override val someProblem: String = "Some Problem"
}

interface BaseFoo {}

Usage:

IdentifiableFoo<Foo0>(2, FooImpl()).doSomething {
    this.noProblem
} // Prints "Hakuna Matata"

IdentifiableFoo<Foo1>(2, Foo1Impl()).doSomething {
    this.someProblem
} // Prints "Some Problem"

Playground link