I'm trying to use generics in a when
, but I get a compiling error if I try to copy the received parameter. The code below exemplifies the problem.
abstract class A { abstract val prop: String};
data class B(override val prop: String) : A();
fun <T : A> execute(t: T): T {
return when (t) {
is B -> {
t.copy() // doesn't compile
// t.copy() as T // compiles
}
else -> t
}
}
The compiling error I get if I try without the casting is:
error: type mismatch: inferred type is Line_19.B but T was expected
Why the compiler can't tell that the types are consistent? Is there a way to avoid the casting?
CodePudding user response:
I think the reason why the compiler isn't smart enough is because it treats data classes as any other class. In particularly, it treats data classes as if they can have subclasses. Consider this example instead:
open class B(override val prop: String) : A() {
fun copy() = B(prop)
}
data class C(override val prop: String) : B(prop)
using your same execute
will throw an exception now on C
instances, because you can't cast to T
since T
is C
but copy()
returns a B
CodePudding user response:
You get that error because the return type is T and T could be any other class different than B, for example you can have a class C that inherits A:
data class C(override val prop: String) : A();
and you can call execute(C(""))
so the return type now is C
so the code will fail because inferred type is B but T was expected
, your function can't return C
and B
at the same time.
You have to solutions for this but your function will be useless if you apply them, the first one is to change the return type to A
and the second one is to change the return type to Any