Is it normal that one adds useless `else` branch e...
# getting-started
m
Is it normal that one adds useless
else
branch even if not needed in Kotlin 1.7? See say https://github.com/streetcomplete/StreetComplete/commit/1972a7139bff92e894474d1d3d1969b83da2d375 For example
Copy code
private fun wat(element: StackUnderflow) {
    when (element) {
        is Unicorn -> {}
        is Multicorn -> {}
        else -> {}
    }
}
requires useless
else
where
Copy code
sealed class StackUnderflow
sealed class Unicorn(val surface: Surface) : StackUnderflow()
sealed class Multicorn : StackUnderflow()
sealed class Tricorn(val surface: Surface) : Multicorn()
sealed class Doublecorn(val surface: Surface) : Multicorn()
is imported from another file.
j
It's normal in the case of the enum in your link.
when
statements became exhaustive like
when
expressions. In 1.6 it was just a warning, but it was raised to error in 1.7. See the notes of 1.6 release. Also the original issue for more information: https://youtrack.jetbrains.com/issue/KT-47709
👍 1
It's not "unnecessary" per se, it forces the developer to explicitly declare the intent of doing nothing. A lot of bugs came from the fact that people were using
when
statements listing all cases, but then someone adds a new possibility (new enum value or sealed class subtype), and suddenly such
when
statements would silently become no-ops. Now, it will fail compilation unless the dev actually adds a branch for the new value, even if just to explicitly do nothing.
Regarding the case of the code that you shared inline here, it shouldn't force you. But I find it odd that you're using sealed classes for leaves here. Interestingly, removing the
sealed
keyword on the leaf classes seems to solve the issue: https://pl.kotl.in/xinFLOmDq Maybe a bug?
m
It's not "unnecessary" per se,
in general I agree but in this case it was triggered and demanding
else
branch in several places where all currently existing solutions were covered! So future addition will swallowed by useless
else
branch demanded now
Copy code
sealed class StackUnderflow
sealed class Unicorn(val surface: Surface) : StackUnderflow()
sealed class Multicorn : StackUnderflow()
class Tricorn(val surface: Surface) : Multicorn()
class Doublecorn(val surface: Surface) : Multicorn()
is not triggering it
j
Yep, that's what I was doing in my playground link above. This does look like a bug
m
curiously
Copy code
fun main() {
    println("aaa")
}

private fun wat(element: StackUnderflow) {
    when (element) {
        is Unicorn -> {}
        is Multicorn -> {}
    }
}

class Surface

sealed class StackUnderflow
sealed class FooBar: StackUnderflow()
sealed class Unicorn(val surface: Surface) : StackUnderflow()
sealed class Multicorn : StackUnderflow()
class Tricorn(val surface: Surface) : Multicorn()
class Doublecorn(val surface: Surface) : Multicorn()
works
🤔 1
despite that FooBar is not handled
Any idea is it an actual bug and is it worth reporting? If yes - any idea where I should report it?
despite that FooBar is not handled
maybe that is because
sealed
class cannot be instantiated?
and then example with fully sealed class gets confusing error because such variable cannot exist?
j
maybe that is because
sealed
class cannot be instantiated?
Yeah I was about to say that. It seems to behave fine with realistic hierarchies. If you have a sealed class without children, it cannot be instantiated so it's ok to skip it.
That said, it's interesting that if the whole hierarchy is sealed (like in your initial example), it breaks compilation. It's not consistent with the fact that there are no possible instances
In your real life use case, are all the concrete classes covered?
m
Copy code
sealed class StackUnderflow
sealed class FooBar: StackUnderflow()

data class Unicorn(val surface: String) : FooBar()
data class Multicorn(val surface: String, val note: String) : FooBar()
class Tricorn : FooBar()
data class Doublecorn(val surface: String) : StackUnderflow()

private fun wat(element: StackUnderflow) {
    when (element) {
        is Unicorn -> {}
        is Multicorn -> {}
        is Tricorn -> {}
        is Doublecorn -> {}
    }
}
that is my real case: and real fun is that in one file it compiles and in another not
it compiles in Kotlin playground
j
Is the non-compiling
when
statement in a different module than the sealed class hierarchy? I remember seeing similar issues in a big multi-module project
m
yes, something was broken with packages file was in different package than code claimed and things compiled but with weird effects
Nevertheless this fully sealed category maybe may deserve bug report. Not sure is "esoteric class structure produces cryptic errors" is even a bug.
Thanks for help!
j
I think it's worth reporting, then the Kotlin team can choose to dismiss as "won't fix" if they don't think it's worth addressing. The place to report would be the Kotlin project in YouTrack: https://youtrack.jetbrains.com/issues/KT
Also worth checking whether it's only in the IDE or if the compilation fails also in command line - it might not be addressed to the same people