Difficulty of compareTo on floats/doubles
Frank van Heeswijk
fvheeswijk at outlook.com
Fri Aug 1 09:05:11 UTC 2014
Alex,
You gave the following class setup:
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));
Correct me if wrong, but I was under the impression that value types could not hold object type references.
My reasoning would be that the real values are stored directly on the stack, instead of a reference.
Could anyone confirm or deny this?
- Frank
> Date: Thu, 31 Jul 2014 15:25:30 -0700
> Subject: Re: Difficulty of compareTo on floats/doubles
> From: timeroot.alex at gmail.com
> To: john.r.rose at oracle.com
> CC: valhalla-dev at openjdk.java.net
>
> 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