[LW10] Value equality
Brian Goetz
brian.goetz at oracle.com
Wed Oct 17 21:03:15 UTC 2018
If we expect values to “work like an int”, then |==| comparisons on
value types should work like they do on primitives:
|value class Point { ... } ... client code ... /* mutable */ Point
location; void setLocation(Point p) { if (p != location) {
fireExpensivePropertyChangeEvent(location, p); this.location = p; } } |
Users will reasonably expect this idiom to work, just as they would for
|int| properties.
There have been at least four suggested treatments of |val==|:
* Illegal; compilation error
* Always false; user must follow up with |.equals()| test
* Substitutibility test — are these the same value
* Delegate to |.equals()| (call this “deep substitutibility”)
I think the first is unreasonable and should be discarded, based on the
above illustration of failure to “work like an int”; I think the second
is the same.
We expect generic code to use the LIFE idiom:
|(x == y) || x.equals(y) |
The LIFE idiom arose because |ref==| is fast, and so we can optimize
away the potentially expensive |.equals()| call when called with
identical objects. But, if the |val==| test becomes more expensive, then
what started out as an optimization, might lead to duplication of
nontrivial work, because the |.equals()| implementation may well also
have an |==| test. But, we don’t want to let the optimization tail wag
the dog here.
Separately, we have been reluctant to push value substitutibility into
|acmp|, for fear of perturbing the performance model there. So, let’s
posit a |vcmp|, a sibling to |{ildf}cmp|, and translate |val==| to that,
and let |acmp| continue to return false when either operand is a value.
Now, for pure value code, like the above, we translate |val==| to
|vcmp|, and we work like an int. And for generic code, the LIFE idiom:
|x == y || x.equals(y) |
(when |x| and |y| are of type |T|) translates to an |acmp| backed up by
an |invokevirtual|, and when |T| is specialized to a value, the |acmp|
is fast and always false, and when specialized to a reference, is fast
and computes |ref==|. I believe this gives everyone what they want:
* value equality is intuitive and appropriately fast
* Existing generics continue using LIFE, and get fast (enough)
translation both for reference and value instantiations
* Generic code that forgets |.equals()| is equally wrong for reference
and value instantiations
* Generic code that goes straight to |.equals()| works correctly for
reference and value instantiation
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20181017/2e78d1da/attachment-0001.html>
More information about the valhalla-spec-experts
mailing list