<div dir="ltr"><div style="font-family:monospace" class="gmail_default">Hello Amber Dev Team,<br><br>Currently in Java, the following is permitted.<br><br>   sealed interface SealedInterface {}<br>   record TypeA() implements SealedInterface {}<br>   record TypeB() implements SealedInterface {}<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final SealedInterface someValue = new TypeA();<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case TypeA a -> 1;<br>            case TypeB b -> 2;<br>         <br>         };<br>   <br>   }<br>   <br>However, the following is not permitted.<br><br><br>   sealed interface SealedInterface {}<br>   record TypeA() implements SealedInterface {}<br>   enum TypeB implements SealedInterface { B; }<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final SealedInterface someValue = new TypeA();<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case TypeA a -> 1;<br>            case TypeB.B -> 2;<br>         <br>         };<br>   <br>   }<br><br>The following is also not permitted.<br><br><br>   sealed interface SealedInterface {}<br>   enum TypeA implements SealedInterface { A; }<br>   enum TypeB implements SealedInterface { B; }<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final SealedInterface someValue = TypeA.A;<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case TypeA.A -> 1;<br>            case TypeB.B -> 2;<br>         <br>         };<br>   <br>   }<br><br>In both of the above failing cases, I receive the following message.<br><br>   ScratchPad.java:132: error: constant expression required<br>            case TypeA.A -> 1;<br>                      ^<br><br>It seems the only way to get rid of the error message is to split the switch expression into 2 each time we see an enum and want to know its value.<br><br>Here is for the first failing example.<br><br><br>   sealed interface SealedInterface {}<br>   record TypeA() implements SealedInterface {}<br>   enum TypeB implements SealedInterface { B; }<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final SealedInterface someValue = TypeB.B;<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case TypeA typeA -> 1;<br>            case TypeB typeB -> <br>               switch (typeB)<br>               {<br>                  case B -> 2;<br>               };<br>         <br>         };<br>   <br>   }<br>   <br>And here is for the second failing example.<br>   <br>   sealed interface SealedInterface {}<br>   enum TypeA implements SealedInterface { A; }<br>   enum TypeB implements SealedInterface { B; }<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final SealedInterface someValue = TypeA.A;<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case TypeA typeA -> <br>               switch (typeA) <br>               {<br>                  case A -> 1;<br>               };<br>            case TypeB typeB -> <br>               switch (typeB)<br>               {<br>                  case B -> 2;<br>               };<br>         <br>         };<br>   <br>   }<br>   <br><br>I can understand the error message well enough -- an enum value is not considered a constant expression.<br><br>But the following code is not only permitted, but also exhaustive, like my very first example.<br><br><br>   enum TypeABC { A, B, C, ; }<br>   <br>   private void mixingEnumsUnderTheSameSealedInterfaceDuringAPatternMatch()<br>   {<br>   <br>      final TypeABC someValue = TypeABC.A;<br>   <br>      final int result = <br>         switch (someValue)<br>         {<br>         <br>            case A -> 1;<br>            case B -> 2;<br>            case C -> 3;<br>         <br>         };<br>   <br>   }<br><br>I understand how switch expressions are the vehicle we are using to deliver exhaustive pattern matching for objects. However, the fact that 2 very different concepts are sharing the same vehicle (and have to take turns being the driver) means that we end up in some frustrating potholes.<br><br>For starters, records and enums organically play well together. There are some concepts best modeled by an enum, and others where a record is a better choice. So if your domain of possible options encourages you to use the 2 together, why does the language make it so hard to do so when doing exhaustiveness checks?<br><br>In some of the articles/videos/etc. about pattern matching by some of the language designers (Brian Goetz's Data Oriented Programming article, for example), we see a new pattern that involves using a record with no fields as form of data representation.<br><br>Consider this example.<br><br>   sealed interface Division {}<br>   record DivideByZero() implements Division {}<br>   record DivisionResult(double answer) implements Division {}<br>   <br>I understand and accept how, in this situation, a separate record type under the same sealed interface is a perfectly acceptable solution to model an irrepresentable state.<br><br>However, because of the fact that switch expressions don't let me mix enum value cases easily with record type cases, I find myself leaning more towards record type cases as a complete replacement for enum values. This is because I don't want to deal with the head ache of trying to get exhaustiveness checking while trying to keep my problem visible on one screen.<br><br>And yet, the language as is seems to outright discourage enums for switch expressions. After all, records can model everything enums can, but enums can't model everything records can. And since switch expressions make it easier to use records instead of enums, why use enums at all?<br><br>But that's a serious problem. Yes, a record can model data the same way an enum can, but that doesn't mean that it is always a drop in replacement, let alone a good one. There are instances where using a class/record type as opposed to an enum value would be problematic at best for your application.<br><br>I will stop considering hypotheticals and simply ask -- am I missing something? Is this something that we plan to solve later, but isn't a priority now? Is this not even a problem at all and I am looking at things the wrong way?<br><br>Thank you for your time and help!<br>David Alayachew</div></div>