Enum vs Record vs Sealed types

Brian Goetz brian.goetz at oracle.com
Fri Jan 3 21:48:28 UTC 2020

I agree that all of these pattern matches should be expressible.

Under the current plan, we get there (at least) by:
  - RED is a constant pattern (well, Color.RED is a constant pattern, 
  - Color(var red, _, _) is a deconstruction pattern, with an explicit 

The feature you are suggesting -- call it "record-style enum 
declarations", is a sound one; such an enum would acquire fields, 
constructors, deconstructors, and accessors, just like records.  It has 
come up a few times already; the reason we haven't done it so far is 
that the return-on-complexity is less than for records.  (It has its 
share of extra spec and compiler behavior, but the user benefit is less 
-- until we get to deconstruction patterns, it is just being able to 
omit the field and ctor declarations, which is something but not all 
that much.)  So we are holding this feature "on the shelf" until it 
seems more likely to pay its way.

(Further, we will want the exhaustiveness analyzer to be able to 
determine that the following switch is exhaustive:

     switch (paint) {
         case RED: ...
         case BLACK: ...
         case WHITE: ...
         case LinearGradient(...): ...

by observing that RED/BLACK/WHITE covers Color, and Color+LinearGradient 
covers Paint.)

On 1/2/2020 3:52 PM, Remi Forax wrote:
> Now that the design of Record is mostly stabilized, i think we should talk about the relation between an enum, a record and a sealed type.
> As we have done with records, we can work backward from the pattern matching switch to see what we need for an enum.
> So let suppose that like Java2D, we fill a shape with a Paint, Paint being an interface between a solid color and a gradient.
> sealed Paint permits Color, LinearGradient { }
> enum Color implements Paint{
>    RED(255, 0, 0), BLACK(0, 0, 0), WHITE(255, 255, 255);
>    private final int red, green, blue;
>    ...
> }
> record LinearGradient(Point start, Color startColor, Point end, Color endColor) implements Paint {
>    int getRed(int x, int y) { ... }
>    int getGreen(int x, int y) { ... }
>    int getBlue(int x, int y) { ... }
> }
> In that case, we may want to be able to switch on a special value (like RED), on an enum and on a Gradient which is a record.
> int redAt(Paint paint, int x, int y) {
>    return switch(paint) {
>      case RED -> 255;
>      case Color(var red, _, _) -> red;
>      case LinearGradient gradient -> gradient.getRed(x, y);
>    };
> }
> So should we allow record components on an enum with the following rule:
> - either an enum use the record like syntax
>    enum Color(int red, int green, int blue) { ... }
>    and in that case, no supplementary fields are allowed.
> - or an enum doesn't use the record like syntax and in that case, it's the classical enum.
> The other solution, is to wait to have de-constructor, in that case we may not need a special syntax for enum.
> Rémi

More information about the amber-spec-experts mailing list