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 classorangy
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>