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

Vitaly Davidovich vitalyd at gmail.com
Tue Jul 11 12:44:27 EDT 2017


Integer and friends have public constructors, so they can't really be value
based classes to begin with (at least as far as value based is defined).

But beside that, value based class warnings are really the same thing as
the warnings with regard to autoboxing and the box cache in the JDK, except
value based permits *all* instances to be cached, and since there's no way
to create your own (short of reflection and the like), there's no defined
identity.

I think once VT are introduced, the simplest and most straightforward
approach is to forbid those types from participating in generic methods
where T can be a VT (ie T must be a class/ref type).

On Tue, Jul 11, 2017 at 12:24 PM Gil Tene <gil at azul.com> wrote:

>
> > 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
> >
> >
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
-- 
Sent from my phone
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://cs.oswego.edu/pipermail/concurrency-interest/attachments/20170711/eb8e61f3/attachment-0001.html>


More information about the Concurrency-interest mailing list