Re: Question about pattern matching and sealed types – redundant switch cases

Brian Goetz brian.goetz at oracle.com
Sat Apr 19 17:34:14 UTC 2025


Right, you've built a monad here, and you want to express the happy path 
with a monadic do.  In Haskell you'd write this as:

     do
         something <- getSomething()
         result <- doThingWithSomething(something)

and let the language desugar it accordingly.  But you can do this 
yourself in Java!

     sealed interface Result<T> permits Ok, Err {
         <U> Result<U> andThen(ThrowyFunction<T, U> f);
         static<T> Result<T> of(ThrowySupplier<T> s) { ... }
     }

and then express your code as:

     Result.of(() -> getSomething())
           .andThen(C::doThingWithSomething)
           ...

No nested code needed.


On 4/19/2025 1:26 PM, Andreas Berheim Brudin wrote:
> Thank you both for the quick replies.
>
> I guess the fact that b1 and b2 is available outside of the if, hints 
> at some kind of flow-based type analysis (even though the new type is 
> implicitly declared in the pattern), but I would then have proven 
> Brian's point - that once that door is open, people will ask for more.
>
> But given the semantics of Java, I understand that this doesn't fit 
> very well. The reason I ask was that we use a Result type (Ok/Err) 
> quite a lot, and the biggest complaint is the nestedness of the code, 
> which often becomes:
> return switch(getSomething()) {
>   case Err(var e) -> yield someError(e);
>   case Ok(var something) -> {
>     yield switch (doThingWithSomething(something)) {
>       case Err(var e) -> yield someOtherError(e);
>       case Ok(var result) -> etc...
>   }
> }
>
> I guess you don't have any quick fixes for that other than resorting 
> to traditional exception handling.
>
> Best,
> Andreas
>
> On Sat, Apr 19, 2025 at 7:08 PM Remi Forax <forax at univ-mlv.fr> wrote:
>
>
>
>     ------------------------------------------------------------------------
>
>         *From: *"Andreas Berheim Brudin" <andreas.brudin at gmail.com>
>         *To: *"amber-dev" <amber-dev at openjdk.org>
>         *Sent: *Saturday, April 19, 2025 6:17:43 PM
>         *Subject: *Question about pattern matching and sealed types –
>         redundant switch cases
>
>         Hi all,
>
>         I'm new to the list—apologies if this has been discussed
>         before, and thanks in advance for your time.
>
>         I have a question about pattern matching with sealed types.
>         Consider this example:
>
>         sealed interface A permits B, C {}
>         record B(String b1, String b2) implements A {}
>         record C(String c) implements A {}
>
>         A myVar = ...;
>         if (!(myVar instanceof B(var b1, var b2))) {
>             return switch (myVar) {
>                 case C(var c) -> c;
>                 case B b -> throw new IllegalStateException("should
>         not happen");
>             };
>         }
>         // use b1, b2
>
>         Here, I want to keep an early-return style, but since I need
>         to return a value from C, I have to use a switch. This leads
>         to redundancy: we've already tested myVar is not a B, so that
>         case should be statically unreachable.
>
>         My questions:
>
>         1. Is there any consideration or ongoing work to allow the
>         compiler to automatically eliminate such unreachable cases?
>
>
>     The short answer is no :)
>
>     Long answer,
>       (1) myVar does not change its type, it is declared as an A, it
>     always be an A (Groovy or Kotlin behave differently, they use flow
>     typing)
>       (2) the type system of Java has no notion of exclusion, the type
>     A but not B does not exist
>       (3) instanceof and switch does not have the same semantics,
>     instanceof has no notion of exhaustiveness while a switch on a
>     sealed type has.
>
>     so because of (1) the type of myVar can not be changed, because of
>     (2) its new type inside the if can not be "A but not B" and
>     because of (3) the new type can not be only C.
>
>
>
>         2. If only one case remains (in this case, C), could it be
>         possible to treat the variable as a C directly without
>         requiring an explicit switch?
>
>
>     No,
>
>
>
>         Again, apologies if this has already been discussed. I'd
>         appreciate any pointers to relevant threads or JEPs if so.
>
>
>     The relevant JEPs are JEP 394 (for instanceof) and 441 (for switch).
>
>
>
>         Thanks,
>         Andreas
>
>
>     regards,
>     Rémi
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20250419/488093e9/attachment-0001.htm>


More information about the amber-dev mailing list