Some thoughts about the recent discussion on Member Patterns.

David Alayachew davidalayachew at gmail.com
Fri Apr 5 15:56:25 UTC 2024


This makes a lot of sense. So, value classes that would like to make use of
pattern-matching are going to be the ones that need this window. That makes
perfect sense to me. Ty vm!

On Fri, Apr 5, 2024, 8:59 AM Brian Goetz <brian.goetz at oracle.com> wrote:

> The question of "why don't you just turn Optional into an algebraic data
> type, and be done with it" is valid, and has been asked before (though,
> usually it is not asked so constructively.)  In many ways this is the
> "obvious" answer.
>
> So, why have we doggedly refused to do the "obvious" thing?  Because
> object modeling is not the only consideration for important platform
> classes like Optional.
>
> In particular, Amber is not the only force that is moving the platform
> forward; there is also Valhalla.  And we would very much like Optional to
> be a value type, to gain all the benefits that can confer.  But the "why
> don't you just model it as the sum of None|Some(t)" approach is
> incompatible with that.
>
> So the reason we've "ignored the obvious" (and been willing to pay extra
> costs elsewhere) is that we are trying to balance both the object model and
> the runtime costs, so that people can "just use Optional" and get the best
> of both worlds.
>
> (This game is harder than it looks!)
>
>
>
> On 4/4/2024 9:19 PM, David Alayachew wrote:
>
> Hello Amber Dev Team,
>
> I wanted to chime into the recent discussion about Member Patterns, but on
> a side topic. I decided to make this a separate thread to avoid distracting
> from the main discussion.
>
> In that discussion, I saw Brian Goetz make the following claim.
>
> > ## Exhaustiveness
> >
> > There is one last syntax question in front of us: how to
> > indicate that a set of patterns are (claimed to be)
> > exhaustive on a given match candidate type.  We see this
> > with `Optional::of` and `Optional::empty`; it would be
> > sad if the compiler did not realize that these two
> > patterns together were exhaustive on `Optional`. This is
> > not a feature that will be used often, but not having it
> > at all will be repeated irritant.
> >
> > The best I've come up with is to call these `case`
> > patterns, where a set of `case` patterns for a given
> > match candidate type in a given class are asserted to be
> > an exhaustive set:
> >
> > ```
> > class Optional<T> {
> >     static<T> Optional<T> of(T t) { ... }
> >     static<T> Optional<T> empty() { ... }
> >
> >     static<T> case pattern of(T t) for Optional<T> { ... }
> >     static<T> case pattern empty() for Optional<T> { ... }
> > }
> > ```
> >
> > Because they may not be truly exhaustive, `switch`
> > constructs will have to back up the static assumption of
> > exhaustiveness with a dynamic check, as we do for other
> > sets of exhaustive patterns that may have remainder.
> >
> > I've experimented with variants of `sealed` but it felt
> > more forced, so this is the best I've come up with.
>
> Later on, I saw Clement Charlin make the following response.
>
> > # Exhaustiveness
> >
> > The `case` modifier is fine, but the design should leave
> > room for `case LABEL` or `case (LABEL1, LABEL2)` to
> > delineate membership in exhaustive set(s), as a potential
> > future enhancement.
>
> To be explicit, I am assuming that we will eventually be able to
> exhaustively deconstruct Optional using something like the following.
>
> switch (someOptional)
> {
>
>     case null               -> System.out.println("The Optional itself is
> null?!");
>     case Optional.of(var a) -> System.out.println("Here is " + a);
>     case Optional.empty()   -> System.out.println("There's nothing here");
>
>     //no default clause needed because this is exhaustive
>
> }
>
> Once pattern-matching lands for normal classes, Optional is almost
> guaranteed to be the class most frequently deconstructed/pattern-matched.
> And since it does not use sealed types, it will really push a lot of people
> to model exhaustiveness as a set of methods.
>
> It's kind of frustrating.
>
> One article that captures my frustration well is from Alexis King --
> "Parse, don't Validate" [1].
>
> In it, she talks about the value of parsing data into a container object,
> with the intent of capturing and RETAINING validation via the type name.
>
> String validEmailAddress vs record ValidEmailAddress(String email) {/**
> Validation logic in the canonical constructor. */}
>
> The moment that the String validEmailAddress leaves the local scope where
> the validation occurred, its validation is no longer known except through
> tracing. But having a full-blown type allows you to assert that the
> validation has already been done, with no possible chance for misuse or
> mistakes.
>
> I guess my question is, in what instances would we say that modeling a set
> of patterns rather than a set of types would be better? The only argument
> that I can think of is conciseness. Or maybe we don't want to poison our
> type hierarchy with an edge case scenario. That point specifically seems to
> be the logic that Optional is following.
>
> My hesitation comes from the fact that pattern sets feel a little leaky.
> And leaky gives me distress when talking about exhaustiveness checking.
>
> With sealed types, if I want to implement SomeSealedInterface, I **MUST**
> acknowledge the question of exhaustiveness. There's no way for me to avoid
> it. My implementing type MUST be sealed, final, or non-final. And even if I
> implement/extend one of the implementing types of SomeSealedInterface, they
> either propogate the question, or they opt-out of exhaustiveness checking.
> Bullet proof!
>
> But adding a pattern to a class does not carry the same guarantee. If I
> add a new pattern that SHOULD have been part of the exhaustive set, but
> isn't, I have introduced a bug. This same bug is NOT POSSIBLE with sealed
> types. Hence, leaky.
>
> I guess my thoughts could be summed up as the following -- I feel like we
> are making an escape-hatch for Optional that I don't think would be worth
> the weight if there was any other way for Optional to be exhaustive. And if
> that is truly true, does that REALLY justify doing this? Feels tacked onto
> the side and leaky imo.
>
> And I will close by saying, I actually used to think this was a good idea.
> I have said so on multiple occasions on this exact mailing list. But the
> more that I think about it, the more that I see no real good reason to do
> this other than "Optional needs it".
>
> * Conciseness? Not a strong argument. Conciseness should be used to
> communicate a semantic difference, not just to shorten code. Think if
> statements vs ternary expressions.
>
> * Semantic difference? Barely, and not in a way that isn't otherwise
> possible. It's just when clauses with exhaustiveness attached tbh. You're
> better off modeling it explicitly. Again, Parse, don't validate.
>
> Thank you all for your time and help!
> David Alayachew
>
> [1] = https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20240405/c1df8a1a/attachment-0001.htm>


More information about the amber-dev mailing list