Devon Humes
03/08/2018, 8:58 PMsealed class Parent {
class Child : Parent()
}
interface Factory<T : Parent>
class FactoryBuilder {
fun <T : Parent> build(item: T): Factory<T> {
return when(item) {
is Parent.Child -> {
object : Factory<Parent.Child> {
}
}
}
}
}
Andreas Sinz
03/08/2018, 9:18 PMwhen
cannot be exhaustive, because you allow T
to be any subclass of Parent
and thus T
must not be a sealed class anymoreAndreas Sinz
03/08/2018, 9:19 PMsealed class Parent {
open class Child : Parent()
}
class ChildChild : Parent.Child()
class ChildChild2 : Parent.Child()
FactoryBuilder().build(ChildChild2()) //Valid code, but ChildChild2 is not a sealed class
orangy
orangy
Child
is not an open
classorangy
Factory
interface is invariant, so Factory<Parent.Child> is not assignable to Factory<T> (even if compiler could figure out, that Parent & Child are the only options)orangy
Andreas Sinz
03/08/2018, 9:25 PMorangy
sealed
classes system controls if the change will be in a single module.Devon Humes
03/08/2018, 9:28 PMAndreas Sinz
03/08/2018, 9:30 PMorangy
orangy
when
exhaustiveness is a bug, please report it. If you write it as when (item as Parent)
it works, and even highlights as
as a redundant cast.Andreas Sinz
03/08/2018, 9:33 PMwhen
exhaustiveness can be determined only for sealed classses, right?orangy
interface Factory<out T : Parent>
so that Factory<Child>
is assignable to Factory<Parent>
. It doesn’t fix the error, which also looks like a problem I don’t understand (on a holiday evening at 00:35 🙂 ).orangy
Devon Humes
03/08/2018, 9:38 PMAndreas Sinz
03/08/2018, 9:42 PMwhen
is not exhaustive, because T
can be any subclass and the compiler doesnt check whether all the subclasses are finalorangy
is
worksorangy
class ChildChild : Parent.Child()
, check for is Parent.Child
will be true
, and hence openness of Parent.Child
is irrelevant.orangy
when
is not exhaustive, because the check is checking only for the type itself (T
in this case) and not its bounds.Andreas Sinz
03/08/2018, 9:46 PMitem: Parent
it works fineorangy
Andreas Sinz
03/08/2018, 9:49 PMwhen
can only be exhaustive for a sealed class
, but T
can be Child
too which is an ordinary classDevon Humes
03/08/2018, 9:49 PMsealed class Parent {
class Child : Parent()
}
fun <T : Parent> test(item: T) {
when(item) {
is Parent.Child -> println()
}
}
seems to compile just fine.Devon Humes
03/08/2018, 9:49 PMAndreas Sinz
03/08/2018, 9:50 PMwhen
so it doesn't check exhaustivenessAndreas Sinz
03/08/2018, 9:53 PMitem: Parent
and cast the objects to Factory<T>
Devon Humes
03/08/2018, 9:54 PMDevon Humes
03/08/2018, 9:55 PMAndreas Sinz
03/08/2018, 9:57 PMAndreas Sinz
03/08/2018, 9:57 PMDevon Humes
03/08/2018, 9:57 PMAndreas Sinz
03/08/2018, 10:39 PMT
is a subclass of Parent
and thus having branches for all direct subclasses of Parent
indeed covers every possible caseAndreas Sinz
03/08/2018, 10:41 PMFactory<T>
because its invariant. In your example we know that inside is Parent.Child ->
its actually a Parent.Child
so Factory<Parent.Child>
is fine, but if the class is open and your item
is a subclass of Parent.Child
it will fail because Factory<Parent.Child> != Factory<ChildSubclass>