[concurrency-interest] Should I avoid compareAndSet with value-based classes?

Aleksey Shipilev shade at redhat.com
Tue Jul 11 13:30:04 EDT 2017


On 07/11/2017 06:22 PM, Gil Tene wrote:
> To test the notion that == "means what you think it means" in some places.
> Lets take your example a couple of steps farther:

> Class AnnotatedTime {
>       String annotation;
>       long secondsSinceEpoch;
>       long nanosInSecond;
>       Instant instant;
> 
>       boolean isExactSameInstant(Instant other) {
>            return (instant == other);
>       }
>  }
> 
>  HashMap<Long, Instant > instanceCache = new HashMap<>();
> 
>  Instant i1 = Instance.ofEpochSecond(1000);
>  Instant i2 = Instance.ofEpochSecond(1000);
>  
>  AnnotatedTimes annotatedTime = new AnnotatedTime();
>  annotatedTime1.annotation = "Time at 1000"; 
>  annotatedTime1. secondsSinceEpoch = 1000;
>  annotatedTime1. instant = i1;
> 
>  instanceCache.put(1000L, i1);
> 
>  A. (i1 == i2)  // We all agree it may be true or false depending on implementation details

Yup.

> B. (i1 == i1)  // You say it must remain true. I say it could validly be
> false. This is a computation of a boolean expression.
I assume you have a highly-paid language lawyer on retainer than could justify
this :) I do think that referential equality stays reflexive, no matter the
nature of reference you are comparing.

The reflexivity seems to come from reference equality operator definition in
15.21.3: "At run time, the result of == is true if the operand values are both
null or both refer to the same object or array; otherwise, the result is false".
I have a hard time coming up with a definition of "same" that is not reflexive.
Can you do it?

The only way out from here is to claim that either == is not reference
comparison, or there is some sort of conversion is taking place before ==. This
is the case for auto-boxed primitives, for example. For Instant case, you cannot
claim either: it is a reference type, and reference comparisons do not need
conversions.

I guess "real" value types, if implemented, would experience this:

 MyValueType v1; // <--- *not* a reference type

 // if "==" is a value comparison, should pass
 // if "==" is a reference comparison, *and* prior boxing, may fail
 assert(v1 == v1);

In fact, spec may be allowed to produce new instance on every single boxing.
Which will render reference CAS -- that requires boxing -- useless, if that what
OP originally asked.

But, there are no non-reference types yet, except for primitives, which makes
this construction moot for all Java's up to and including 9.

>  C. (i1 == annotatedTime. instant) // You say this must be true as well??

Yes, because it compares the reference to the same object.

>  D. (annotatedTime1.isExactSameInstant(i1)) // Is this required to be true?

Yes, because it compares the reference to the same object.

>  E. (i1 == instanceCache.get(1000L)) // And this must also be true??

Yes, because it compares the reference to the same object.


> If you say that B,C,D,E must all be true (which would presumably be
> self-consistent), you are basically saying that even tho the spec says so,
> Instant cannot be freely replaced with other Instants that are .equals() with
> it in computations and method invocations. At that point, nothing
> distinguishes a value-based class from a regular class that is immutable.
> E.g. Instant and Integer have the same defined behavior according to this
> interpretation, and all mention of a value-based class in the spec is
> basically a no-op.

My interpretation is that "value-based class" today is the property of the
producing expressions -- Instant.ofEpochSecond in this case -- extended to every
producing expression (whether it is a language construct, factory call, etc)
that can give the instance.


> Note that long-standing immutable classes with clean .equals() and hashcode
> behaviors (like Integer, Long, etc.) have not been specified to be
> value-based classes. Presumably due to historical compatibility reasons,
> since the identity of instances of those classes certainly carries meaning,
> and B-E above would all have to be true for them. In contrast, all current
> classes that are defined as value-based classes have been defined so from
> their inception. If you want to interpret the specification of value-based
> classes as not contradicting the behavior of e.g. Integer, why the
> definition? And why is Integer NOT a value-based class?
I think "value-based class" language is provisional for "do not rely on
identity, even if it is defined for the objects you will be getting". Integer,
as you say, have already leaked the identity in public, and we are done there,
the guy is disqualified.

In this parlance, saying "Instant is like primitive/Integer" is far worse
language than actually spelling out the "unknown identity" rules with
"value-based class" text. Having these rules spelled out eases switching them to
real value types, with appropriate spec changes. But, it does not give a blanket
approval for doing so, it just minimizes the damage.

I understand one could claim "JVM is allowed to ignore identity for value-based
classes, because it is claimed to be unpredictable anyway", and probably lawyer
up to say it is spec-legal. Although it would be fun to see the defense where
Javadoc trumps the core JLS.

Still, I think the interpretation of "identity stays unknown, but still behaves
like an object" is saner from quality of implementation, principle of least
astonishment, "don't break Java" standpoints.

How will Valhalla deal with these problems, we shall see. My bet is on
value-type-specific comparisons (which should catch CAS in its wake), plus
boxing where the references are needed (which would capitalize on what we
learned to love about Java's primitives).

I think this CAS example is interesting to discuss in valhalla-dev@, where it
actually matters, not here.

Thanks,
-Aleksey



-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: OpenPGP digital signature
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170711/3645a0c6/attachment.sig>


More information about the Concurrency-interest mailing list