dave08
03/05/2024, 2:29 PMsealed interface Foo
and @JvmInline value class Foo1(val value: String): Foo
and @JvmInline value class Foo2(val value: String): Foo
I'd like to have a method on Foo
that Foo1
and Foo2
implement to add a Foo1
to another Foo1
and a Foo2
to another Foo2
... at the calling site I just know it's a Foo
, how could I implement this?dave08
03/05/2024, 2:34 PMfun <T : Foo> add(other: T): T
in Foo
doesn't help too much since I don't want to be able to add a Foo1
to a Foo2
...dave08
03/05/2024, 2:38 PMsealed interface Foo {
fun add(other: ?): ?
}
@JvmInline value class Foo1(val value: String): Foo {
override fun add...?
}
@JvmInline value class Foo2(val value: String): Foo {
override fun add...?
}
val fooMap: Map<String, Foo> = ...
val fooMap2: Map<String, Foo> = ...
// I need to merge fooMap2 with fooMap1... each type should handle itself
dave08
03/05/2024, 2:39 PMdave08
03/05/2024, 2:42 PMSam
03/05/2024, 2:44 PMa specific key will always have the same type of FooThis feels like the crucial piece of information, but there isn't a simple way to express this in Kotlin's type system. But I think you're right, a
when
statement is fine. There's no need to try and make it polymorphic if it's a sealed class. That's the whole point of sealed classes really.CLOVIS
03/05/2024, 3:59 PMsealed interface Foo {
fun add(other: Nothing): Foo
}
@JvmInline … Foo1 … : Foo {
override fun add(other: Foo1): Foo1
}
@JvmInline … Foo2 … : Foo {
override fun add(other: Foo2): Foo2
}
CLOVIS
03/05/2024, 4:02 PMsealed interface Foo<Self : Foo> {
fun add(other: Self): Self
}
@JvmInline … Foo1 … : Foo<Foo1> {
override fun add(other: Foo1): Foo1
}
@JvmInline … Foo2 … : Foo<Foo2> {
override fun add(other: Foo2): Foo2
}
I can't try at the moment, but I think it does work. However, you can't call the interface-level method (other
is effectively Nothing
), since you can't prove the other argument is of the same concrete class if you don't know the concrete class of the first.CLOVIS
03/05/2024, 4:04 PM// I need to merge fooMap2 with fooMap1... each type should handle itselfThis part is definitely not possible at compile-time, you can only do that with some kind of runtime check. Though with the self-type version, you could just have:
fun Foo<*>.addAuto(other: Foo<*>) {
when {
this is Foo1 && other is Foo1 -> this.add(other)
this is Foo2 && other is Foo2 -> this.add(other)
else -> error("Both arguments should be of the same class; found $this ($this::class) and $other ($other::class)")
}
}
dave08
03/05/2024, 4:56 PMaddAuto
won't have to contain each implementation's logic... which could be nice in this case! I guess that I'm losing out on the advantage of a sealed interface's exhaustive check... but like you said, there's not much choice in the matter...CLOVIS
03/05/2024, 4:57 PMList
you're stuck with when
.dave08
03/06/2024, 11:53 AMsealed interface Foo {
fun add(other: Foo): Foo = other
}
@JvmInline value class Foo1(val value: String): Foo {
fun add(other: Foo): Foo {
require(other is Foo1) { ... }
...
}
}
@JvmInline value class Foo2(val value: String): Foo {
fun add(other: Foo): Foo {
require(other is Foo2) { ... }
...
}
}
dave08
03/06/2024, 11:54 AMCLOVIS
03/06/2024, 12:38 PMKlitos Kyriacou
03/06/2024, 1:09 PMoverride fun add(other: Foo): Foo2
dave08
03/06/2024, 1:18 PMdave08
03/06/2024, 1:20 PMdave08
03/06/2024, 1:23 PMCLOVIS
03/06/2024, 1:27 PM