Difficulty of compareTo on floats/doubles
Alex Meiburg
timeroot.alex at gmail.com
Thu Jul 31 22:25:30 UTC 2014
So the current state is that for...
primitives:
== and != performs bitwise comparison
equals() doesn't exist
Objects:
== and != perform identity testing
equals() is a method that can be overriden
With regards to equality on value types, it sounds like the main proposals
are...
values, option 1:
== performs elementwise testing, via "vcmp"
equals() defaults to vcmp, but can be overridden
values, option 2:
== and equals() perform elementwise testing, via "vcmp". equals() is
final.
values, option 3:
== doesn't exist on the unboxed values.
equals() defaults to vcmp, but can be overridden
And then on polymorphic generics that could be primitive, value, or Object,
there are
generics, option 1:
== will perform just as == would on the corresponding
Object/primitive/value
equals() will call the method on the Object/value, and
Float.equals()/Integer.equals()/etc. on primitives
generics, option 2:
== is an identity check on Objects, and equals() on primitive/value
equals() will call the method on the Object/value, and
Float.equals()/Integer.equals()/etc. on primitives
generics, option 3:
== doesn't exist on polymorphic variables
equals() will call the method on the Object/value, and
Float.equals()/Integer.equals()/etc. on primitives
and the situation you're describing is option 1 for values, and option 3
for generics. (The numbering is arbitrary, of course).
Would allowing equals to be overridden be worth it, on value types?
Although certainly mostly a lack of imagination, I feel like the use cases
to redefine it would be limited -- and there is one other thing to
consider, of how the equality check should recurse onto objects members of
the value type. For instance, given a situation like
class Bar {
int f;
public Bar(int f){ this.f = f; }
public boolean equals(Object that){ return (that instanceof Bar) &&
((Bar)that).f == f; }
}
final __ByValue class Foo {
int x;
Bar y;
}
Foo a = __MakeValue(5, new Bar(10));
Foo b = __MakeValue(5, new Bar(10));
System.out.println(a == b);
System.our.println(a.equals(b));
Then my first expectation would be for them to print "false" and "true",
respectively. That is, if "==" were a vcmp, it would check x's for integer
bitwise equality, and the reference y the same way. The "equals" method I
would intuitively expect to do similar bitwise comparison on x, but a call
to y.equals(). This follows along with the general thought process that
when I'm treating it like an int I want a quick and "dumb" equality check,
whereas the more class-seeming equals() call is something I can expect to
be a "deep" check. I may be alone in expecting this. :) But if others agree
that it would be a logical behavior, then I would support defining == to be
recursive == on reference fields, and equals() to be a (probably final)
method doing the above.
-- Alexander Meiburg
2014-07-31 13:56 GMT-07:00 John Rose <john.r.rose at oracle.com>:
> On Jul 31, 2014, at 12:43 PM, Alex M <timeroot.alex at gmail.com> wrote:
>
> > strange problems
>
> The essential point here is discussed in passing (see "simple
> relationals") in the value type prospectus.
> http://cr.openjdk.java.net/~jrose/values/values.html
>
> Yes, there are a lot of these strange problems that arise from forcing
> both primitives and objects under one type bound.
>
> More generally, the semantic oddities of "==" for float, double, and
> references make it very tricky indeed to apply "==" (and other operators,
> notably "+") to extremely polymorphic variables bounded by "any".
>
> Although it may not be practical in the end, my personal preference would
> be to deprecate or disallow operators on polymorphic variables, and express
> everything with method invocation.
>
> Method invocation on a non-reference value can be uniformly and simply
> defined by delegation to a boxed version of the value. If we define new box
> types (not impossible though difficult) we can take extra care to have the
> ad hoc polymorphism be as consistent as possible across the expanded range
> of types. We provide for such consistency already in the documentation of
> interfaces like Comparable and (as Joe explained) methods like
> Double.compareTo.
>
> Pre-existing boxes are probably not adequate to this. Null references may
> also require a "boxing" rule of some sort.
>
> See also the "vcmp" instruction in the value types prospectus. For value
> types we think we can make a compatible story of how to cope with "==" and
> ".equals": "==" is bitwise and ".equals" is a method call (possibly boxed,
> but the user cannot observe whether that happens).
>
> Bottom lines: Consistent ad hoc polymorphism is hard, especially when
> unifying legacy types. And see "vcmp" for bitwise semantics and extend it
> if necessary to primitives. But try hard to do most things in terms of
> methods, which is more flexible and explicit.
>
> — John
More information about the valhalla-dev
mailing list