That reminds me a problem I thought I had in STYX...<p>For a few months I had the feeling that a good switch-expression requires the bottom type... It turns out that the `assert(0)` idiom, used in a lambda, is sufficient:<p><pre><code> var u32 a = switch b do {
1 => 2,
/* ... */
else => function(): u32 => {assert(0, "crash");}()
};
</code></pre>
The `else` case (similar to C `default`) simply crashes the program but the type system is happy because the lambda return type is compatible.
I think the transformative potential for error handling in Java cannot be overstated. Effectively, this means exceptions can be handled as errors without polluting the return type with an ever-growing list of error-monads.<p>The following example shows this nicely:<p>> Future<String> f = ...<p>> switch (f.get()) {<p>> case String s -> process(s);<p>> case throws ExecutionException(var underlying) ->
throw underlying;<p>> case throws TimeoutException e -> cancel();<p>> }<p>Note that I don't get the hate for exceptions. Sometimes, handeling the error somewhere up the callstack is exactly the right solution. The problem was that Java did not have convenient syntax for handeling exceptions at call-site.<p>FYI: There was also an interesting discussion in the Java mailing lists also going into some implementation details regarding the representing bytecode:<p><a href="https://mail.openjdk.org/pipermail/amber-spec-experts/2023-December/003959.html" rel="nofollow noreferrer">https://mail.openjdk.org/pipermail/amber-spec-experts/2023-D...</a>
I really think the `case throws` is brilliant.<p>Next, lets add a `never` type to make this legal.<p><pre><code> var foo = switch (bar) {
case String s -> s,
case Number n -> return,
};</code></pre>