<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">Short answer: we understand
        the problem, and it will eventually be addressed.<br>
        <br>
        Switch started with a lot of baggage, and accreted more over the
        years.  Fully rehabilitating switch will take some time. 
        Support for enums in switches remains, currently, in the domain
        of "legacy behavior"; to complete the rehabilitation we'll need
        to interpret constant case labels as constant _patterns_.  This
        is on the list, and we're working through it, but we haven't
        gotten there yet.  <br>
        <br>
        Fans of algebraic data types in Haskell will feel this gap, in
        Haskell's version of enums and records are the same thing:<br>
        <br>
            data List t = Nil | Cons t (List t)<br>
        <br>
        Nil is like an enum; Cons is like a record.  It is perfectly
        reasonable to switch over something that has both, we're just
        not there yet.<br>
      </font></font><br>
    <div class="moz-cite-prefix">On 10/16/2022 10:54 PM, David Alayachew
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAA9v-_PTavuDngu0PTPkyOoa2HOaGeuRJ-p2Ga0U+CQGHHaUeA@mail.gmail.com">
      
      <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>
    </blockquote>
    <br>
  </body>
</html>