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

Gil Tene gil at azul.com
Tue Jul 11 12:22:48 EDT 2017


> On Jul 10, 2017, at 2:53 AM, Aleksey Shipilev <shade at redhat.com> wrote:
> 
> On 07/10/2017 11:22 AM, Andrew Haley wrote:
>> Indeed.  I already quoted the language in the JLS I'm relying on, and
>> said that I find it convincing.  I believe that 15.21.3, "Reference
>> Equality Operators == and !=" would have to be changed in order for
>> your interpretation of reference equality to be correct.
>> 
>> So let's move on to another matter, the JVM specification, and the way
>> that Java maps on to the JVM.  In the JVM, the instruction if_acmpeq
>> is supposed to return true if value1 = value2.  So,
>> 
>>   dup; if_acmpeq
>> 
>> is bound to succeed.
>> 
>> You could argue that it is theoretically possible that Java could be
>> compiled onto the JVM in some other way, so that your interpretation
>> of the JLS would be correct, but I don't think it's much to worry
>> about.  You could also argue that the section which describes
>> value-based classes implicitly changes the JVM specification, but I'd
>> like to see that in writing.
> 
> I remember this was the early confusion with lambdas, which had the relaxed
> notion of identity too. And there was the same confusion of "OMG, I can get the
> exception doing '==' on lambda?!". But that only extended to "you don't know
> what would the evaluation result of lambda expression be: it might be equal to
> something else, or not".
> 
> That is:
> 
>  Runnable r1 = () -> {};
>  Runnable r2 = () -> {};
>  assert (r1 == r2);                       // deliberately unspecified
>  assert (r1.getClass() == r2.getClass()); // deliberately unspecified
>  assert (r1 == r1);                       // keeps being true!
>  assert (r2 == r2);                       // keeps being true!
>  assert (r1.getClass() == r1.getClass()); // keeps being true!
>  assert (r2.getClass() == r2.getClass()); // keeps being true!

The [very important] difference is that Runnable is NOT a value-based class. But Instant is. Runnable never said anything about the use of identity resulting in unpredictable effects, Instant does. Runnable never said anything about being allowed to be freely substitute with other Runnables that are .equals() in any computation. Instant does.

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
 B. (i1 == i1)  // You say it must remain true. I say it could validly be false. This is a computation of a boolean expression.
 C. (i1 == annotatedTime. instant) // You say this must be true as well??
 D. (annotatedTime1.isExactSameInstant(i1)) // Is this required to be true?
 E. (i1 == instanceCache.get(1000L)) // And this must also be true??

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.

If you say e.g. that B must be true but either C, D, or E doesn't have to be true. Where do you draw the line? Is it at local variables vs. heap storage? Is it in parameter passing? What things are allowed to freely replace one Instant with some other Instant that is .equals() to it, and what things aren't?

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 that for value objects, whether they are really implemented on JVM, or
> they are just declared in Javadoc, the same thing applies. This stance in docs
> is the key: "[Value-based classes:] - do not have accessible constructors, but
> are instead instantiated through factory methods which make no committment as to
> the identity of returned instances;". The rest of the properties seem to be
> derived from that unreliable identity.
> 
> In other words, "no commitment" reads as "identity is unknown" rather than
> "identity is non-existent". Unknown identity is still reflexive, symmetric,
> transitive. The identity of the value type *box* that you get from the
> expression should be deliberately unspecified to provide implementation freedom,
> but once you get the boxed reference, it is bound by the same JLS rules Andrew
> quotes.
> 
> In yet other words, "value-based class" tells to be careful about the identity
> semantics of producing expressions, but it does not relax the semantics of the
> boxed references you get from them either explicitly or implicitly. This is
> pretty much like current primitive autoboxing works :)
> 
> Thanks,
> -Aleksey
> 
> 



More information about the Concurrency-interest mailing list