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,
anyway.)
- Color(var red, _, _) is a deconstruction pattern, with an explicit
deconstructor
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