<div dir="auto">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!</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Apr 5, 2024, 8:59 AM Brian Goetz <<a href="mailto:brian.goetz@oracle.com">brian.goetz@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><u></u>

  
  <div>
    <font size="4" face="monospace">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.  <br>
      <br>
      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.  <br>
      <br>
      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.  <br>
      <br>
      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.  <br>
      <br>
      (This game is harder than it looks!)<br>
      <br>
      <br>
    </font><br>
    <div>On 4/4/2024 9:19 PM, David Alayachew
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <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>
          <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>
          <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/" target="_blank" rel="noreferrer">https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/</a><br>
        </div>
      </div>
    </blockquote>
    <br>
  </div>

</blockquote></div>