Sealed interface/class question... I have a seale...
# getting-started
c
Sealed interface/class question... I have a sealed interface X and two implementing classes A and B I can get an exhaustive when statement from them. But are if statements not supported at all? In my scenario of only the 2 implementations if seems cleaner than when but i'd like the compiler to infer from the if. But it doesn't seem too.
Copy code
val x: X = something()
if (x is A) return
// x should now smart cast to B
I'm guessing this just isn't supported. Do we know if K2 will be adding it?
j
What do you want to happen if someone adds a new subtype? I usually prefer exhaustive `when`s everywhere so it's clear
💯 2
If the code after the
if
doesn't make use of special properties of
B
, this addition of a
C
subtype wouldn't fail compilation (but might change the behaviour of the program)
c
I guess in the 2 cases example adding C would cause it not to be able to cast to B anymore so it'd be a compilation error. But I can see how being in a when the whole thing is clearer.
Different language and goals but Typescript felt slightly better than Kotlin in some ways with this stuff. (Kotlin is still by far the superior language of course)
In my example above x cannot be an instance of A. It can only be an instance of B. But the compiler doesn't recognise that.
m
Realistically, this is exactly what an exhaustive
when
is for though. On the other hand, inverting your
if
check will get your smart casting working how you want, albeit without the early exit and happy-path-left-alignment.
Copy code
val x: X = something()
if (x is B) {
    // x is now smart cast to B
}
You could handle the B case easily enough too in separate function to make it cleaner if you don't like the indent:
Copy code
val x: X = something()
if (x is B) handleB(x)

...

fun handleB(b: B) {}
j
Or just
if (x !is B) return
for that matter - and that would be expressing the intent better if the point is to ensure that you have a
B
instance after the
if
(which would be resilient to addition of subtypes).
in the 2 cases example adding C would cause it not to be able to cast to B anymore so it'd be a compilation error
That is only if you actually use the fact that it's smart-cast to B after the
if
. But if you just do things assuming it's a
B
, but without relying of type-safe properties of
B
, it could compile fine but behave wrong. My point is that such
if
statements are dangerous because they don't account for future additions of subclasses, regardless of whether the compiler was able to smart cast or not. This is why I usually push for exhaustive `when`s over
if
statements for these things, and also why we should avoid using
else
in those `when`s. And in turn, it makes your problem with smart casting go away.
Don't get me wrong, I agree it would indeed be better if the compiler did that smart cast after the
if
of course, all I'm saying is that I don't find it that much of an issue in practice because the code pattern itself is fishy in the first place.