I’m trying to learn more about generics. I current...
# announcements
k
I’m trying to learn more about generics. I currently have
Copy code
interface Id

inline class BarId(val value: Int): Id
inline class BazId(val value: Int): Id

sealed class Foo<T: Id> {
   abstract val id: T
   data class Bar(...): Foo<BarId>()
   data class Baz(...): Foo<BazId>()
}

fun <T: Foo<U>, U: Id> myFun(entity: T): U = TODO()
Suppose I need to add a function to
Foo
that will take an Id param and spit back out a child class (the one that is affiliated with the Id implementation in question). So
myBar.changeId
should take
BarId
and spit out
Bar
. For example.
Copy code
sealed class Foo<T: Id> {
   ...
   abstract fun <T: Foo<U>, U: Id> changeId(id: U): T
}
I’m sitting here with
Copy code
data class Bar(...): Foo<BarId>() {
   override fun changeId(id: BarId): Bar = TODO()
}
not really knowing what to put for
changeId
. Obviously the implementation is going to be
changeId(id: BarId): Bar = this(id=id)
but I have to put some generics in the signature somewhere or else compiler/linter tells me this does not match the signature of Foo.changeId, which it is intended to override.
s
Since Bar and Baz are data classes, you can just use the
copy
method to create a new instance with a different ID. Maybe you simplified your use-case before posting here, so not sure this will actually work for your real world purposes.
Also, this is pretty nasty, but it works
Copy code
sealed class Foo<U : Id, S : Foo<U, S>> {
    abstract val id: U
    abstract fun changeId(id: U): S

    data class Bar(override val id: BarId) : Foo<BarId, Bar>() {
        override fun changeId(id: BarId): Bar = this.copy(id = id)
    }

    data class Baz(override val id: BazId) : Foo<BazId, Baz>() {
        override fun changeId(id: BazId): Baz = this.copy(id = id)
    }
}
👍 1
k
Thanks.
copy
is what I was using, but I omitted it so my question wouldn’t push potential answers in the direction I’d (possibly suboptimally) chosen. My issue was more around how to keep using the generics. I didn’t realize that I could reuse the class generic param in the function without re-declaring a generic in the function header itself. Problem solved, thanks!
s
Yeah.. that type of “recursive generics” (not sure if that’s a proper name, just what it looks like to me) is a bit odd.. but can help define a “self” type