Alejandro Serrano.Mena
10/05/2026, 11:55 AMmbonnin
10/05/2026, 12:13 PMelse? -> part? Can't the compiler infer from the declaration that the enum is incomplete and in that case allow the regular else -> syntax without a warning? (And make a warning if it's not there?)Alejandro Serrano.Mena
10/05/2026, 12:15 PMelse? covers a slightly different use case: when you want your code to actually break if the enum/sealed class gets a new value. That is, with else? the rest of the branches must still be exhaustive.mbonnin
10/05/2026, 12:15 PMAlejandro Serrano.Mena
10/05/2026, 12:16 PMenum? you should expect users to use else, not else?, since they should not care about you adding new members (that's what this is all about). But we have a subset of cases where this exhaustiveness is somehow advisable (e.g., a utils library accompanying a core library, where both co-evolve)mbonnin
10/05/2026, 12:20 PM99% of the timeShouldn't I want
else? -> most of the time though? If I bump my library dependency and a new value comes up, I want to be made aware of it and press [Alt + Enter] to introduce the new case, which I understand is only possible with else? ->?Alejandro Serrano.Mena
10/05/2026, 12:22 PMmbonnin
10/05/2026, 12:25 PMbreaking changeWe were discussing this just this morning π I wouldn't necessarily say it's a breaking change or else everything can be described as a breaking change. My use case is I have sealed classes representing GraphQL AST nodes. When new syntax is introduced, there are new nodes but I wouldn't describe it as a breaking change though. You can keep parsing the older documents and it's working the same. Now of course if you want to support the newer syntax, you'll need the new AST nodes so I'd use
else? -> in that casebod
10/05/2026, 12:27 PMelse is mandatory for an incomplete enum
β’ βI want to break if there are new valuesβ case: add e.g. @ForceExhaustive on the when which disallows elsembonnin
10/05/2026, 12:29 PMI want to break if there are new valuesIt's not just that I think. It's "I want to break if there are new build time values but still have a fallthrough for 'unknown at build time' values"
mbonnin
10/05/2026, 12:30 PMelse catches everything
β’ else? catches everything but errors at build time if there are unhandled cases known at build timeAlejandro Serrano.Mena
10/05/2026, 12:33 PMbod
10/05/2026, 12:34 PMelse for the second case is a good trade-off (vs introducing new syntax). What I mean: if you want to handle incomplete enums, and break when there are new values -> you can't can't have a fallthrough else in your when , you must list all values.bod
10/05/2026, 12:35 PMmbonnin
10/05/2026, 12:35 PMkeep the conversation focused on the syntaxJust want to make sure I understand what the proposed syntax is doing ^^
Alejandro Serrano.Mena
10/05/2026, 12:37 PMelse to preserve binary compatibility
β’ "this branch applies to future-and-unknown cases"
Our preliminary investigation shows that some people care about that distinction, and this is why we are thinking of a new form of elsembonnin
10/05/2026, 12:38 PMelse? myself but I feel weird being in the 1% πHristijan
10/05/2026, 1:47 PM? already means nullability in Kotlin. String?, ?., ?: all mean "might be null." enum? reads as "nullable enum" and else? reads as "optional else" or "matches null."
Neither reading is correct in my head Kotlin has been consistent about ? = null, and this would break that no?
else? signals the opposite of what it does. A (in the form)? suggests something looser but else? is the stricter form of it as it makes the compiler require every known case
Might be a good idea to lean on how Swift does thinfs:
such as else unknown -> (Swift precedent: @unknown default), or else future ->
What about
nonexhaustive enum class Version { V1, V2, V3 }
when (v) {
V1 -> "original"
V2 -> "refined"
V3 -> "awesome"
else unknown -> "unknown"
}
Then it would read as
switch v {
case .v1: "original"
case .v2: "refined"
case .v3: "awesome"
@unknown default: "unknown"
}
In Swift interop too?
Not sure about nonexhaustive word just threw it out there as an ideaAlejandro Serrano.Mena
10/05/2026, 2:19 PMhfhbd
10/05/2026, 2:52 PMhfhbd
10/05/2026, 2:55 PMephemient
10/05/2026, 3:10 PMopen enum class is not too bad, but I think an annotation would be better for compatibility. no new keywords, existing parsers (eg ktlint) continue working, can be produced by existing formatters (eg kotlinpoet)
@NonExhaustive enum class Version
on the other side, I'd rather see
when (this) {
else -> unreachable()
}
where the compiler will warn or error if the code is reachable. similarly better for compatibility, and also potentially more generally useful as wellrusshwolf
10/05/2026, 4:11 PMopen for a modifier since it's familiar and seems pretty analogous to existing usage. But if we're applying this to sealed classes as well as enums then we'd have open sealed declarations which could be confusing. We do already have internal external declarations, so there's precedent for combining modifiers in Kotlin that sound like opposites in English, but that still might not be something we want more of.phldavies
10/05/2026, 4:39 PMopen enum as "someone else can extend this" which isn't the intent here.Zac Sweers
10/05/2026, 9:36 PMopen enum would be passible but I think open sealed would not.
What about extensible + _? With the underscore as an alternative to a new unknown keyword
extensible enum class Version { V1, V2, V3 }
fun Version.render(): String = when (this) {
Version.V1 -> "original"
Version.V2 -> "refined"
Version.V3 -> "awesome"
else _ -> "unknown"
}Zac Sweers
10/05/2026, 9:36 PM_ else optionZac Sweers
10/05/2026, 9:39 PMCLOVIS
10/06/2026, 7:36 AM? , because this feature has nothing to do with nullability.
I kinda like else unknown ->CLOVIS
10/06/2026, 7:39 AMopen enum . else incomplete -> is ok, but incomplete enum isn't beautiful.
extensible enum class β¦
else extended β
It's a bit too similar to Java's extends , but I doubt users would find it confusing since enums can't be part of hierarchies anywayCLOVIS
10/06/2026, 7:43 AMCLOVIS
10/06/2026, 7:43 AMwhen (β¦) {
Foo.One ->
Foo.Two ->
else if extended ->
}
I think that ties a bit better with what we're used to write π€
that's a breaking change if the user has a variable called extended though, right? unless the variable is given priority over the keyword, but that's a bit strangeZac Sweers
10/06/2026, 3:42 PMextensible enum class Version { V1, V2, V3 }
fun Version.render(): String = when (this) {
Version.V1 -> "original"
Version.V2 -> "refined"
Version.V3 -> "awesome"
else _ -> "unknown"
}
it also captures well that you don't know what it isCLOVIS
10/06/2026, 3:44 PMelse _ but it's easy to think it means "all other cases" whereas it means "all cases that appear at runtime without being known at compile time"
I agree it aesthetically fits into the language but I'm worried it sends the wrong message about what it doesphldavies
10/06/2026, 3:45 PMelse unknown -> is clear - _ makes me think of pattern matchingZac Sweers
10/06/2026, 3:46 PMZac Sweers
10/06/2026, 3:47 PMCLOVIS
10/06/2026, 3:47 PMCLOVIS
10/06/2026, 3:50 PMelse variant? github.com/ziglang/zig/issues/2524 just describes a regular else
Edit, found it: https://www.reddit.com/r/Zig/comments/ttucl3/what_it_a_nonexhaustive_enum/louiscad
10/06/2026, 4:18 PMelse! -> ?
The exclamation mark suffix is already used in Kotlin to refer to something unknown: the nullability for an unannotated Java type (platform types), in the IDE.
To me, it'd make sense to also use it for unknown other enum cases.
It also speaks less about nullability than else? -> to me, being unrelated to known nullability, and the elvis operator, which has the question mark as a suffix to :.CLOVIS
10/06/2026, 4:19 PM!! is also about nullability, and Foo! is not really a part of the language, it can't appear in source files
Also Java is considering String! for non-nullable types
But I agree that Foo! in Kotlin means "the compiler can't check something", which matches quite well with "the compiler is afraid of new members added in the future"russhwolf
10/06/2026, 5:01 PMelse! makes me think it might crash if it sees something unexpected, when this is really the opposite.louiscad
10/06/2026, 5:27 PMelse!! to actually make it crash? πphldavies
10/06/2026, 5:28 PMelse?! for when it's truly supposed to be exhaustive.Zac Sweers
10/07/2026, 3:55 PM? has high enough value prop + it's usually the last character in that expression, else! -> feels like a lexical rollercoasterDylan Sale
10/15/2026, 7:00 AM_. I may be incorrect but I think you could skip the else altogether in that case because I don't think it's a currently a valid variable name in that position.
fun Version.render(): String = when (this) {
Version.V1 -> "original"
Version.V2 -> "refined"
Version.V3 -> "awesome"
_ -> "unknown"
}
Seems better to me because you don't have the issue of someone accidentally missing the modifier and doing else -> { } , disabling the exhaustiveness check.
I just saw the Zig version and I like how it uses it. It's basically the pseudocode I'd write if I was partially defining an enum in a design doc or something.