Value equality

Remi Forax forax at univ-mlv.fr
Wed May 18 19:17:40 UTC 2016


Hi John, Brian,
John suggest it in it's mail, ==(val, val) and ==(any,any) can be not aligned, it will be weird but has its own good. 

P5: merge P3 and P4, ban ==(valuetype, valuetype) but make ==(any, any) the new operator
    that does an x == y || x.equals(y) on a reference type, an x.equals(y) on a value type and x == y on primitive type.

Rémi

----- Mail original -----
> De: "Brian Goetz" <brian.goetz at oracle.com>
> À: "John Rose" <john.r.rose at oracle.com>
> Cc: valhalla-spec-experts at openjdk.java.net
> Envoyé: Mercredi 18 Mai 2016 16:57:24
> Objet: Re: Value equality
> 
> Great summary of the options.
> 
> For those who didn't read the whole thing:
>   - CE is bitwise equality -- "are these two things identical copies"
>   - OE is calling Object.equals()
>   - NE (for values) is the synthetic "recurse with == on primitive
> components, NE on value components, and OE on reference components"
> 
> If it were 1995, and we were inventing Java (and we didn't have our
> heads addled with an interpreter-based cost model), what would we do?  I
> think we'd bind ==(ref,ref) to OE, with an (uglier-named) API point for
> CE (e.g., Objects.isSameReference) which would be used (a) for
> known-interned things, (b) for IdentityHashMap, (c) as a default
> implementation of Object.equals(), and (d) possibly as a
> short-circuiting optimization *inside* overrides of equals().
> 
> This hypothetical world (call it J') still gives users the choice of CE
> vs OE whenever they want, while nudging users towards OE (by giving it
> the prime syntactic real estate) which is probably what they want most
> of the time.
> 
> Why didn't we do this in 1995?  Hard to know (I'll ask James next time I
> see him), but I'd posit two main forces:
> 
>   - C bias.  Since C has *only* CE (and it was desirable to make Java
> feel like "a safer C") it probably seemed like a big improvement already
> to offer programmers both CE and OE on all references, and binding == to
> OE probably seemed too radical at the time.
> 
>   - Cost-model bias.  In the Java 1.0 days, pointer comparison was
> probably 100x faster in the interpreter than a virtual call to
> Object.equals().  If binding == to OE was even considered, it was
> probably deemed implausible.
> 
> Of course, both of these feel a bit silly 20 years later, but here we
> are.  So, in a J' world, what would we do with ==(val,val)?  I think it
> would be a no-brainer -- bind it to NE, since Java developers would
> already associate == with a deeper comparison.  Then we'd just have to
> adjust whatever the API point for CE is to also accomodate CE on values,
> and we'd be done.
> 
> But, we don't live in J' world.  So our choices become:
> 
> P1: Bind ==(val,val) to CE, as we do with refs.  Optimization challenges
> with the usual (a==b || a.equals(b)) idiom [1], but the rules work the
> same for values and refs.
> 
> P2: Bind ==(val,val) to NE.  This is J' world for values and J world for
> refs.  (With even bigger optimization challenges for the (a==b ||
> a.equals(b)) idiom.)  Rules are different for values and refs, meaning
> (a) users will have to keep in mind which world they're in, (b) when
> migrating a class from ref to value they'll have to find and update all
> equality comparisons (!), (c) writing code that's generic over values
> and refs has to use an idiom that works on both, (d) when migrating code
> from ref-generic to any-generic, inspect every equality comparison to
> make sure it's still what was intended.
> 
> P3: Add a new equality operator.  I've already been laughed at enough,
> thank you.
> 
> P4: Ban ==(val,val).  This might be fine in value-only code, but it
> complicates writing generic code, especially migrating generic code.
> 
> 
> [1] John points out that if == is CE, then (a==b||a.equals(b)) will
> redundantly load the fields on failed ==.  But, many equals
> implementations start with "a==b" as a short-circuiting optimization,
> which means "a==b" will be a common (pure) subexpression in the
> resulting expansion (and for values, methods are monomorphic and will
> get inlined more frequently), so the two checks can be collapsed.
> 
> 
> > Going back to op==, there are two plausible options for binding it to
> > new types:
> >
> > (P1) Syntax of op==(val,val) and op==(any,any) binds to CE as with
> > op==(ref,ref).  Therefore, NE is uniformly reached by today's idiom,
> > which traverses value fields twice.
> >
> > (P2) Syntax of op==(val,val) and op==(any,any) is direct access to
> > NE.  CE is reachable by experts at System.isEqualCopy.  The old idiom
> > for NE works also calls equals twice.
> >
> > (P3) Same as P1, op== is uniform access to CE.  New op (spelled
> > "===", ".==", "=~", etc.) is uniform, optimizable access to NE,
> > attracting users away from legacy idiom for NE.
> 
> 


More information about the valhalla-spec-observers mailing list