<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  </head>
  <body>
    <font size="4"><font face="monospace">I don't have an answer for
        you, but I can add some information to the mix.  <br>
        <br>
        Currently there are _nine_ "implementations" of `==`; one for
        references, and one for each of the eight primitives. 
        Regardless of whether or not they are perfect tests of
        substitutibility (curse you, floating point), the eight
        primitive `==` functions are highly domain-specific.  They can
        be so because the primitives are monomorphic.  In a sense, we've
        allowed primitives to "overload" `==` because monomorphism means
        we can define `==` with full knowledge of the domain, and
        without worry about non-well-definedness or the various other
        problems of `equals` in extensible class hierarchies (as EJ
        exhaustively catalogued.)  <br>
        <br>
        What's being proposed here is that we evolve `Object==` from
        "compare identities" to a case analysis, to account for the fact
        that Object will describe more things: <br>
        <br>
            case (IdentityObject a, IdentityObject b) ->
        identity==(a, b)<br>
            case (ValueObject a, ValueObject b) -> (isNull(a) ==
        isNull(b)) && (type(a) == type(b)) <br>
                                                                   
        && (state(a) == state(b))<br>
            default -> false<br>
        <br>
        Just as `identity==` was the best we could do as a default on
        polymorphic identity objects, this is the best we can do on
        polymorphic mixed identity/value objects.  (There's a whole
        digression into overloading `==` on value types, but I'm not
        going to go there right now.)<br>
        <br>
        While we're not making the problem of "`==` is unreliable"
        better, and arguably making it incrementally worse by making it
        work in more cases that look a little like the cases in which it
        is unreliable, we *are* making something better here: you can
        now use `.equals()` everywhere.  One of the complains about `==`
        is that sometimes you use `==` and sometimes you use `.equals()`
        and sometimes you can accidentally use one where you should use
        the other.  But this is because you couldn't previous use
        .equals() on primitives, so an `equals()` method would
        necessarily do things like:<br>
        <br>
            boolean equals(Object o) { <br>
                return o instanceof Foo f<br>
                    && f.size == this.size<br>
                    && f.name.equals(this.name);<br>
            }<br>
        <br>
        What stinks here is that at each point, you have to ask yourself
        "equals, or =="?  Now you can have a fixed rule: always say
        `.equals()`:<br>
        <br>
      </font></font><font size="4"><font face="monospace"><font size="4"><font face="monospace">    boolean equals(Object o) { <br>
                    return o instanceof Foo f<br>
                        && f.size.equals(this.size)   // works
            on int!<br>
                        && f.name.equals(this.name);<br>
                }<br>
            <br>
            (The equals method on primitives is monomorphic so will JIT
            away, for anyone worried about the performance.)  <br>
            <br>
            It is a little sad because we had to resolve the problem by
            using the unfortunate spelling all the time, because `==`
            got the good name, but that's not a new problem.  But it
            means the cognitive load can disappear if we train ourselves
            to uniformly use `.equals()`.  <br>
            <br>
            We will surely have about a million calls to make `===` or
            `eq` or something else sugar for `.equals()`.  We can
            consider that, but I don't think its essential to do that
            now.  <br>
          </font></font><br>
      </font></font><br>
    <div class="moz-cite-prefix">On 6/15/2022 1:51 PM, Kevin Bourrillion
      wrote:<br>
    </div>
    <blockquote type="cite" cite="mid:CAGKkBktQ7ndHAvvZ_v+HA7RO6K0EuZGBLo+RosrX2s-ihFMdXA@mail.gmail.com">
      
      <div dir="ltr">What I think I understand so far:
        <div><br>
        </div>
        <div>The current plan for `==` for all bucket 2+ types (except
          the 8 _primitive_ types, as I still use the word) is to have
          it perform a fieldwise `==` comparison: identity equality for
          bucket 1 fields, what it's always done for primitive fields,
          and of course recurse for the rest.</div>
        <div><br>
        </div>
        <div>If we consider that the broadest meaning of `a == b` has
          always been "a and b are definitely absolutely
          indistinguishable no matter what", then this plan seems to
          compatibly preserve that, which makes sense for purposes of
          transition.</div>
        <div><br>
        </div>
        <div>What concerns me:</div>
        <div><br>
        </div>
        <div>It's good for transition, at least on the surface, but it's
          a bad long-term outcome.</div>
        <div><br>
        </div>
        <div>Users hunger for a shorter way to write `.equals()`, and
          they will think this is it. I would not underestimate the
          pushback they will experience to writing it out the long way
          in cases where `==` at least *seems* to do the right thing.
          Because in some number of cases, it *will* do the same thing;
          specifically, if you can recurse through your fields and never
          hit a type that overrides equals().</div>
        <div><br>
        </div>
        <div>This is extremely fragile. A legitimate change to one type
          can break these expectations for all the types directly or
          indirectly depending on it, no matter how far away.</div>
        <div><br>
        </div>
        <div>In supporting our Java users here, there's no good stance
          we can take on it: if we forbid this practice and require them
          to call `.equals`, we're being overzealous. If we try to help
          them use it carefully, at best users will stop seeing
          `Object==Object` as a code smell (as we have spent years
          training them to do) and then will start misusing it even for
          reference types again.</div>
        <div><br>
        </div>
        <div>btw, why did I say it's good for transition "on the
          surface"? Because for any class a user might migrate to bucket
          2+, any existing calls to `==` in the wild are extremely
          suspect and *should* be revisited anyway; this is no less true
          here than it is for existing synchronization etc. code.</div>
        <div><br>
        </div>
        <div>What's an alternative?:</div>
        <div><br>
        </div>
        <div>I'm sure what I propose is flawed, but I hope the core
          arguments are compelling enough to at least help me fix it.</div>
        <div><br>
        </div>
        <div>The problem is that while we <i>can</i> retcon `==` as
          described above, it's not behavior anyone  really <i>wants</i>.
          So instead we double down on the idea that non-primitive `==`
          has always been about identity and must continue to be. That
          means it has to be invalid for bucket 2+ (at compile-time for
          the .val type; failing later otherwise?).</div>
        <div><br>
        </div>
        <div>This would break some usages, but again, only at sites that
          deserve to be reconsidered anyway. Some bugs will get fixed in
          the process. And at least it's not the language upgrade itself
          that breaks them, only the specific decision to move some type
          to new bucket. Lastly, we don't need to break anyone abruptly;
          we can roll out warnings as I proposed in the email "We need
          help to migrate from bucket 1 to 2".</div>
        <div><br>
        </div>
        <div>A non-record class that forgets to override equals() from
          Object even upon migrating to bucket 2+ is also suspect. If
          nothing special is done, it would fail at runtime just like
          any other usage of `Foo.ref==Foo.ref`, and maybe that's fine.</div>
        <div><br>
        </div>
        <div>Again, I'm probably missing things, maybe even big things,
          but I'm just trying to start a discussion. And if this can't
          happen I am just searching for a solid understanding of why.</div>
        <div><br>
        </div>
      </div>
    </blockquote>
    <br>
  </body>
</html>