Hi everyone! I'm not sure this problem was raised...
# language-proposals
b
Hi everyone! I'm not sure this problem was raised before. I assume it must be a pretty common case, but found no links to discussions. *TL;DR*; it'd be nice to have "smart" exhaustive when statement over sealed types, which would take its generics into the account. Here's an example:
Copy code
sealed interface SealedOf<Type>

object SealedOfString1 : SealedOf<String>
object SealedOfString2 : SealedOf<String>

object SealedOfInt1 : SealedOf<Int>
object SealedOfInt2 : SealedOf<Int>

fun theIssue() {

    // Note that variable restricts the values only to SealedOf<String>
    var subject : SealedOf<String> = SealedOfString1

    // This is the only way to have exhaustive when statement - and it produces a compilation error:
    // Incompatible types: SealedOfInt1 and SealedOf<String>
    when (subject) {
        SealedOfString1 -> TODO()
        SealedOfString2 -> TODO()
        SealedOfInt1 -> TODO()
        SealedOfInt2 -> TODO()
    }

    // This produces warning or error:
    // Non exhaustive 'when' statements on sealed class/interface will be prohibited in 1.7,
    // add 'SealedOfInt1', 'SealedOfInt2' branches or 'else' branch instead
    when (subject) {
        SealedOfString1 -> TODO()
        SealedOfString2 -> TODO()
    }
}
It'd be nice for compiler to understand that
SealedOf<Int>
types cannot be assigned to the variable, and therefore no
SealedOfInt1, SealedOfInt2
branches are needed. Writing
else
branch resolves the compilation error, but that is not why sealed types are used 🙂
👍 1
h
As a workaround you could use another inner class
Copy code
sealed interface SealedOf<Type>

sealed interface SealedOfString: SealedOf<String>
object SealedOfString1 : SealedOfString
object SealedOfString2 : SealedOfString

sealed interface SealedOfInt: SealedOf<Int>

object SealedOfInt1 : SealedOfInt
object SealedOfInt2 : SealedOfInt

fun theIssue() {

    // Note that variable restricts the values only to SealedOf<String>
    var subject : SealedOfString = SealedOfString1

    // This is the only way to have exhaustive when statement - and it produces a compilation error:
    // Incompatible types: SealedOfInt1 and SealedOf<String>
    when (subject) {
        SealedOfString1 -> TODO()
        SealedOfString2 -> TODO()
    }
👍 1
b
Yup, restricting types using another sealed types would work. When you have a lot of generics in the code, however, it's not always possible or convenient to use these restrictions.
r
If I had to bet, this would have something to do with JVM type erasure, which would mean your assumption "`SealedOf<Int>` types cannot be assigned to the variable" is not actually true. But the suggested resolution being a complier error is not exactly great, regardless.
b
Yes! But sealed types check are happening on compile-time – and compiler knows about all the possible subtypes 🙂 For instance, compiler actually adds else branch to the bytecode of exhaustive when statements. It can do the same for this sort of when statements.
👍 1
Where can I propose this language improvement?