<div dir="auto">Most of my points are now defunct, but I will answer just to clear my intent.<div dir="auto"><br></div><div dir="auto">When I said leaky, I was referring to the fact that it is very easy to add a pattern to the class, forget to add it to the accompanying  pattern set, and then introduce a bug. I was more bemoaning the loss of a safety net that was available to us with sealed types, but after rereading again, that doesn't feel like a strong argument at all.</div><div dir="auto"><br></div><div dir="auto">As for the other points Brian proved them wrong. But I do appreciate you expanding on why they are wrong! The constructor point was very useful to communicate the migration incompatibility.</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 5, 2024, 11:50 AM Red IO <<a href="mailto:redio.development@gmail.com" target="_blank" rel="noreferrer">redio.development@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div>Some thoughts on your concerns. <br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 5, 2024, 03:20 David Alayachew <<a href="mailto:davidalayachew@gmail.com" rel="noreferrer noreferrer" target="_blank">davidalayachew@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:monospace">Hello Amber Dev Team,<br><br>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.<br><br>In that discussion, I saw Brian Goetz make the following claim.<br><br>> ## Exhaustiveness<br>> <br>> There is one last syntax question in front of us: how to<br>> indicate that a set of patterns are (claimed to be)<br>> exhaustive on a given match candidate type.  We see this<br>> with `Optional::of` and `Optional::empty`; it would be<br>> sad if the compiler did not realize that these two<br>> patterns together were exhaustive on `Optional`. This is<br>> not a feature that will be used often, but not having it<br>> at all will be repeated irritant.<br>> <br>> The best I've come up with is to call these `case`<br>> patterns, where a set of `case` patterns for a given<br>> match candidate type in a given class are asserted to be<br>> an exhaustive set:<br>> <br>> ```<br>> class Optional<T> {<br>>     static<T> Optional<T> of(T t) { ... }<br>>     static<T> Optional<T> empty() { ... }<br>> <br>>     static<T> case pattern of(T t) for Optional<T> { ... }<br>>     static<T> case pattern empty() for Optional<T> { ... }<br>> }<br>> ```<br>> <br>> Because they may not be truly exhaustive, `switch`<br>> constructs will have to back up the static assumption of<br>> exhaustiveness with a dynamic check, as we do for other<br>> sets of exhaustive patterns that may have remainder.<br>> <br>> I've experimented with variants of `sealed` but it felt<br>> more forced, so this is the best I've come up with.<br><br>Later on, I saw Clement Charlin make the following response.<br><br>> # Exhaustiveness<br>><br>> The `case` modifier is fine, but the design should leave<br>> room for `case LABEL` or `case (LABEL1, LABEL2)` to<br>> delineate membership in exhaustive set(s), as a potential<br>> future enhancement.<br><br>To be explicit, I am assuming that we will eventually be able to exhaustively deconstruct Optional using something like the following.<br><br>switch (someOptional)<br>{<br><br>    case null               -> System.out.println("The Optional itself is null?!");<br>    case Optional.of(var a) -> System.out.println("Here is " + a);<br>    case Optional.empty()   -> System.out.println("There's nothing here");<br><br>    //no default clause needed because this is exhaustive<br><br>}<br><br>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. <br><br>It's kind of frustrating.<br><br>One article that captures my frustration well is from Alexis King -- "Parse, don't Validate" [1].<br><br>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.<br><br>String validEmailAddress vs record ValidEmailAddress(String email) {/** Validation logic in the canonical constructor. */}<br><br>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.<br><br>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.<br><br>My hesitation comes from the fact that pattern sets feel a little leaky. And leaky gives me distress when talking about exhaustiveness checking.<br><br>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!<br><br>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.<br></div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">I don't see how it would be leaky. Adding a case pattern to a class would/should be considered a braking change to the class same as adding a new type to a sealed types hierarchy. Causing compile errors on every previously exhaustive pattern match. </div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:monospace"><br>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.<br><br>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".<br></div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">There is a need for objects to be distinguishable in different states without being split in different types. As much as I love type driven design it isn't the only case for pattern matching. Especially with things like value classes that are fundamentally incompatible with identity based type matching of sealed types. Also old classes that expose constructors can't be turned into a sealed hierarchy without braking api changes. But changing a class from 0 to X case patterns isn't a braking change similar to the addition of generics in the past. </div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:monospace"><br>* 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.<br><br>* 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.</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">Thank you all for your time and help!</div><div class="gmail_default" style="font-family:monospace">David Alayachew</div><div class="gmail_default" style="font-family:monospace"><br></div><div class="gmail_default" style="font-family:monospace">[1] = <a href="https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/" rel="noreferrer noreferrer noreferrer" target="_blank">https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/</a></div></div></blockquote></div></div><div dir="auto"><br></div><div dir="auto">Great regards </div><div dir="auto">RedIODev </div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_default" style="font-family:monospace"><br></div></div>
</blockquote></div></div></div>
</blockquote></div>