Should I avoid compareAndSet with value-based classes?

classic Classic list List threaded Threaded
101 messages Options
123456
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Remi Forax
----- Mail original -----
> De: "Doug Lea" <[hidden email]>
> À: [hidden email]
> Envoyé: Jeudi 6 Juillet 2017 14:25:19
> Objet: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?

> On 07/06/2017 05:13 AM, Andrew Haley wrote:
>> On 06/07/17 04:59, Michael Hixson wrote:
>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>> (and related) operations [1].  Using == to compare instances of
>>> value-based classes may lead to "unpredictable results" [2].  Does
>>> this mean I should avoid using compareAndSet with arguments that are
>>> instances of value-based classes?
>>>
>>> It seems like the documentation clearly tells me "yes, avoid doing
>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>> value for example?
>>
>> java.time.Instant stores times that are longer than a JVM word, so
>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>> that instances which compare equal also have the property of
>> reference equality.  j.t.Instant factories in the Java library are
>> explicitly documented *not* to have this property, so that doesn't
>> help.
>>
>> If you want to be able to CAS a reference to a j.t.Instant, you're
>> going to have to wrap accesses to it in a synchronized block.  This is
>> a direct consequence of the JVM's inability to CAS multi-word objects.
>
> Right. Hoping not add confusion, the underlying issues also arise in
> upcoming Value Types. (https://wiki.openjdk.java.net/display/valhalla/Main)
>
> These "actual" value types will (like primitives) use "==" for
> (possibly multiple component) equality.
> VarHandles for atomic operations will need to use some form of locking.
> Possibilities (not yet fully implemented) include some combination of
> (1) just using a global lock for all values (2) using a pool of locks
> (e.g., hashed on containing object identityHashCode), and/or
> (3) using native hardware transactions on platforms supporting them
> (e.g., recent x86). Plus potential specializations for non-SC VarHandle
> operations (e.g.,  seqlocks for getAcquire).
>
> In principle, you could apply most of these (no HTM) for current uses of
> value-based classes.
>
> -Doug

Value types have no identity so no identityHashCode.

Another alternative is to force the Value Type to implement an interface that will have a method providing the object that will be used to lock.

interface Lockable {
  Object lock();
}

value class MyValues implements Lockable {
  private final Object lock;
  private final Type1 field1;
  ...

  public Object lock() { return lock; }
}

cheers,
Rémi
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Justin Sampson
In reply to this post by Michael Hixson
Howdy,

This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.

It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.

Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.

Cheers,
Justin


On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:

    Forwarding this reply of mine because I forgot to CC the mailing list.
   
   
    ---------- Forwarded message ----------
    From: Michael Hixson <[hidden email]>
    Date: Thu, Jul 6, 2017 at 7:24 AM
    Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
    value-based classes?
    To: Andrew Haley <[hidden email]>
   
   
    On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
    > On 06/07/17 11:41, Alex Otenko wrote:
    >>
    >>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
    >>>
    >>> On 06/07/17 04:59, Michael Hixson wrote:
    >>>> AtomicReference and VarHandle are specified to use == in compareAndSet
    >>>> (and related) operations [1].  Using == to compare instances of
    >>>> value-based classes may lead to "unpredictable results" [2].  Does
    >>>> this mean I should avoid using compareAndSet with arguments that are
    >>>> instances of value-based classes?
    >>>>
    >>>> It seems like the documentation clearly tells me "yes, avoid doing
    >>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
    >>>> VarHandle are exempt somehow.  Otherwise, how do I implement
    >>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
    >>>> value for example?
    >>>
    >>> java.time.Instant stores times that are longer than a JVM word, so
    >>> they cannot be CAS'd in a lock-free way unless a factory guarantees
    >>> that instances which compare equal also have the property of
    >>> reference equality.  j.t.Instant factories in the Java library are
    >>> explicitly documented *not* to have this property, so that doesn't
    >>> help.
    >>
    >> That’s not entirely clear.
    >>
    >> Wouldn’t this loop work:
    >>
    >> volatile j.t.Instant curr = ...
    >>
    >> j.t.Instant next = …
    >> j.t.Instant tmp = ...
    >> do {
    >>   tmp = curr;
    >>   if (tmp.equal(next)) break;
    >> } while(!curr.CAS(tmp, next));
    >>
    >> // assume curr is equal to next
    >
    > Something like that, yes.  But it's going to be evil if there are
    > several high-frequency writers.  If you're doing all that work in
    > order to CAS a timestamp, why not use a synchronized block?  It would
    > at least be less prone to the thundering herd, and we'd generate
    > pretty decent code for that.  It'd be interesting to compare and
    > contrast the two approaches for contended and non-contended cases.
   
    The main reason I reached for AtomicReference is that I thought, "I
    want thread-safe updates to this read-heavy value where writes won't
    get lost if there's contention -- this sounds like the sort of problem
    that java.util.concurrent.atomic solves."
   
    As a minor point, I wanted synchronization on reads to be as
    minor/invisible as possible, to affect the readers' behavior as little
    as possible (in comparison to their behavior when the value they're
    reading a constant value with no synchronization).
   
    But if AtomicReference is simply the wrong tool to use here, I
    shouldn't use it.  That's fine.
   
    >
    >>> If you want to be able to CAS a reference to a j.t.Instant, you're
    >>> going to have to wrap accesses to it in a synchronized block.  This is
    >>> a direct consequence of the JVM's inability to CAS multi-word objects.
    >>
    >> This is confusing.
    >>
    >> Surely this isn’t talking about CASing a reference? The contents of
    >> the object can’t be assumed to have any atomicity properties,
    >> whether it is j.t.Instant or not.
    >
    > I agree.  I'm trying to look at what the OP actually wants to do: I
    > assume this is some kind of atomic timestamp, and the OP wants to be
    > able to CAS an instance of j.u.Instant.
   
    It was more of a general worry and question.  Should I ever use
    AtomicReference with value-based classes?  It sounds like the answer
    is no.
   
    But here's some code that illustrates the specific problem I was
    trying to solve.  I think it "works" right now, but that it's in
    violation of the spec for value-based classes and so possibly not
    future-proof, and I think I understand how to fix it now.  Thanks for
    the tips.
   
        class MutableClock {
   
            static MutableClock create(Instant instant, ZoneId zone) {
                return new MutableClock(
                        new AtomicReference<>(instant),
                        zone);
            }
   
            private final AtomicReference<Instant> instantHolder;
            private final ZoneId zone;
   
            private MutableClock(
                    AtomicReference<Instant> instantHolder,
                    ZoneId zone) {
                this.instantHolder = instantHolder;
                this.zone = zone;
            }
   
            Instant instant() {
                return instantHolder.get();
            }
   
            ZoneId getZone() {
                return zone;
            }
   
            void setInstant(Instant newInstant) {
                instantHolder.set(newInstant);
            }
   
            void add(Duration amountToAdd) {
                // this is the part that uses == and CAS
                instantHolder.updateAndGet(
                      instant -> instant.plus(amountToAdd));
            }
   
            MutableClock withZone(ZoneId newZone) {
                // conveniently, AtomicReference also acts as a
                // vehicle for "shared updates" between instances
                // of my class
                return new MutableClock(instantHolder, newZone);
            }
        }
   
    -Michael
    _______________________________________________
    Concurrency-interest mailing list
    [hidden email]
    http://cs.oswego.edu/mailman/listinfo/concurrency-interest
   

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Alex Otenko
It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen". 

Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.

For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).

We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.

It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.

For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.

One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...

This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.

Sent from my iPad

On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:

:-) the one causing Byzantine failures!

Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.

All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).


Alex


On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:

just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
n  Sebastian
 
From: Concurrency-interest [[hidden email]] On Behalf Of Alex Otenko
Sent: Thursday, July 06, 2017 10:17 AM
To: Gil Tene
Cc: [hidden email]
Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
 
 
On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:

All it is saying is:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
 
a==b && b==c can be true and can be false
 
It also means that even when:
 
  LocalDateTime d = a;
  ...
  (a == d) may or may not be true. And may change whether it is true or not at any time,
 
I meant an even stronger assertion:
 
assert (a==b) == (b==a) : "No Byzantine optimizations"
assert (a==d) == (a==d): “No Byzantine optimizations"
 
Alex
 


 
 
Alex
 
On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:

Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content. 
There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
.equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
 
For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
  int a = 5;
  int b = 5;
  boolean y = (a == b);  // true
 
For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
  Integer a = new Integer(5);
  Integer b = new Integer(5);
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // false
 
And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // unpredictable, undefined, who knows. 
                                         // Could be true, could be false.
                                         // Could theoretically change the values of a or b, or of something else
 


 
On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:

I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.

While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
For example:
- It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
- It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
- It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
- It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).

So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.

— Gil.

> On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
>
> I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
>
> By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
>
> If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
>
>
> On 2017-07-05 09:20 PM, Gil Tene wrote:
>> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
>> — Gil.
>>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
>>>
>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>> (and related) operations [1].  Using == to compare instances of
>>> value-based classes may lead to "unpredictable results" [2].  Does
>>> this mean I should avoid using compareAndSet with arguments that are
>>> instances of value-based classes?
>>>
>>> It seems like the documentation clearly tells me "yes, avoid doing
>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>> value for example?  Do I have to box the value in something that's not
>>> a value-based class first, like AtomicReference<Box<Instant>>?
>>>
>>> -Michael
>>>
>>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
>>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
 
 

Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Alex Otenko
Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.

List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.

Alex

On 6 Jul 2017, at 17:33, Gil Tene <[hidden email]> wrote:

It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen". 

Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.

For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).

We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.

It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.

For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.

One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...

This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.

Sent from my iPad

On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:

:-) the one causing Byzantine failures!

Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.

All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).


Alex


On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:

just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
n  Sebastian
 
From: Concurrency-interest [[hidden email]] On Behalf Of Alex Otenko
Sent: Thursday, July 06, 2017 10:17 AM
To: Gil Tene
Cc: [hidden email]
Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
 
 
On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:

All it is saying is:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
 
a==b && b==c can be true and can be false
 
It also means that even when:
 
  LocalDateTime d = a;
  ...
  (a == d) may or may not be true. And may change whether it is true or not at any time,
 
I meant an even stronger assertion:
 
assert (a==b) == (b==a) : "No Byzantine optimizations"
assert (a==d) == (a==d): “No Byzantine optimizations"
 
Alex
 


 
 
Alex
 
On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:

Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content. 
There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
.equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
 
For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
  int a = 5;
  int b = 5;
  boolean y = (a == b);  // true
 
For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
  Integer a = new Integer(5);
  Integer b = new Integer(5);
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // false
 
And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // unpredictable, undefined, who knows. 
                                         // Could be true, could be false.
                                         // Could theoretically change the values of a or b, or of something else
 


 
On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:

I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.

While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
For example:
- It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
- It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
- It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
- It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).

So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.

— Gil.

> On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
>
> I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
>
> By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
>
> If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
>
>
> On 2017-07-05 09:20 PM, Gil Tene wrote:
>> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
>> — Gil.
>>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
>>>
>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>> (and related) operations [1].  Using == to compare instances of
>>> value-based classes may lead to "unpredictable results" [2].  Does
>>> this mean I should avoid using compareAndSet with arguments that are
>>> instances of value-based classes?
>>>
>>> It seems like the documentation clearly tells me "yes, avoid doing
>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>> value for example?  Do I have to box the value in something that's not
>>> a value-based class first, like AtomicReference<Box<Instant>>?
>>>
>>> -Michael
>>>
>>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
>>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
 
 

Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

David M. Lloyd-3
I sent this from the wrong e-mail address due to MUA change.  Resending...

On Wed, Jul 5, 2017 at 11:20 PM, Gil Tene <[hidden email]> wrote:
> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>
> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>
> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.

How many generic concurrent data structures exist which (to name one
example) use compareAndSet() to update a value in the two-argument
replace() case?  What measures do (or can) these structures take to
prevent these magical value types from being used in these cases?

If we (as the collective concurrency community and as the greater Java
community) allow these magical value types to *actually* stop working
in some logical fashion with == and therefore with CAS, we are utterly
deserving of the chaos that will result.  In particular, it would be a
terrible idea to allow the basic CAS loop to be broken for some Object
subclasses:

   do {
       a = atomic.get();
       b = compute(a);
   } while (! atomic.compareAndSet(a, b));

No amount of performance optimization is worth breaking the
correctness of this fundamental structure.
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Justin Sampson
We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.

To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
- There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
- Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.

This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).

Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.

In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().

Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().

Sent from my iPad

> On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
>
> Howdy,
>
> This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
>
> It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
>
> Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
>
> Cheers,
> Justin
>
>
> On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
>
>    Forwarding this reply of mine because I forgot to CC the mailing list.
>
>
>    ---------- Forwarded message ----------
>    From: Michael Hixson <[hidden email]>
>    Date: Thu, Jul 6, 2017 at 7:24 AM
>    Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
>    value-based classes?
>    To: Andrew Haley <[hidden email]>
>
>
>>>>    On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
>>>>> On 06/07/17 11:41, Alex Otenko wrote:
>>>>
>>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
>>>>
>>>> On 06/07/17 04:59, Michael Hixson wrote:
>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>> (and related) operations [1].  Using == to compare instances of
>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>> instances of value-based classes?
>>>>>
>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>> value for example?
>>>>
>>>> java.time.Instant stores times that are longer than a JVM word, so
>>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>>>> that instances which compare equal also have the property of
>>>> reference equality.  j.t.Instant factories in the Java library are
>>>> explicitly documented *not* to have this property, so that doesn't
>>>> help.
>>>
>>> That’s not entirely clear.
>>>
>>> Wouldn’t this loop work:
>>>
>>> volatile j.t.Instant curr = ...
>>>
>>> j.t.Instant next = …
>>> j.t.Instant tmp = ...
>>> do {
>>>  tmp = curr;
>>>  if (tmp.equal(next)) break;
>>> } while(!curr.CAS(tmp, next));
>>>
>>> // assume curr is equal to next
>>
>> Something like that, yes.  But it's going to be evil if there are
>> several high-frequency writers.  If you're doing all that work in
>> order to CAS a timestamp, why not use a synchronized block?  It would
>> at least be less prone to the thundering herd, and we'd generate
>> pretty decent code for that.  It'd be interesting to compare and
>> contrast the two approaches for contended and non-contended cases.
>
>    The main reason I reached for AtomicReference is that I thought, "I
>    want thread-safe updates to this read-heavy value where writes won't
>    get lost if there's contention -- this sounds like the sort of problem
>    that java.util.concurrent.atomic solves."
>
>    As a minor point, I wanted synchronization on reads to be as
>    minor/invisible as possible, to affect the readers' behavior as little
>    as possible (in comparison to their behavior when the value they're
>    reading a constant value with no synchronization).
>
>    But if AtomicReference is simply the wrong tool to use here, I
>    shouldn't use it.  That's fine.
>
>>
>>>> If you want to be able to CAS a reference to a j.t.Instant, you're
>>>> going to have to wrap accesses to it in a synchronized block.  This is
>>>> a direct consequence of the JVM's inability to CAS multi-word objects.
>>>
>>> This is confusing.
>>>
>>> Surely this isn’t talking about CASing a reference? The contents of
>>> the object can’t be assumed to have any atomicity properties,
>>> whether it is j.t.Instant or not.
>>
>> I agree.  I'm trying to look at what the OP actually wants to do: I
>> assume this is some kind of atomic timestamp, and the OP wants to be
>> able to CAS an instance of j.u.Instant.
>
>    It was more of a general worry and question.  Should I ever use
>    AtomicReference with value-based classes?  It sounds like the answer
>    is no.
>
>    But here's some code that illustrates the specific problem I was
>    trying to solve.  I think it "works" right now, but that it's in
>    violation of the spec for value-based classes and so possibly not
>    future-proof, and I think I understand how to fix it now.  Thanks for
>    the tips.
>
>        class MutableClock {
>
>            static MutableClock create(Instant instant, ZoneId zone) {
>                return new MutableClock(
>                        new AtomicReference<>(instant),
>                        zone);
>            }
>
>            private final AtomicReference<Instant> instantHolder;
>            private final ZoneId zone;
>
>            private MutableClock(
>                    AtomicReference<Instant> instantHolder,
>                    ZoneId zone) {
>                this.instantHolder = instantHolder;
>                this.zone = zone;
>            }
>
>            Instant instant() {
>                return instantHolder.get();
>            }
>
>            ZoneId getZone() {
>                return zone;
>            }
>
>            void setInstant(Instant newInstant) {
>                instantHolder.set(newInstant);
>            }
>
>            void add(Duration amountToAdd) {
>                // this is the part that uses == and CAS
>                instantHolder.updateAndGet(
>                      instant -> instant.plus(amountToAdd));
>            }
>
>            MutableClock withZone(ZoneId newZone) {
>                // conveniently, AtomicReference also acts as a
>                // vehicle for "shared updates" between instances
>                // of my class
>                return new MutableClock(instantHolder, newZone);
>            }
>        }
>
>    -Michael
>    _______________________________________________
>    Concurrency-interest mailing list
>    [hidden email]
>    http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Alex Otenko
Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).

Sent from my iPad

On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email]> wrote:

Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.

List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.

Alex

On 6 Jul 2017, at 17:33, Gil Tene <[hidden email]> wrote:

It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen". 

Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.

For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).

We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.

It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.

For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.

One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...

This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.

Sent from my iPad

On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:

:-) the one causing Byzantine failures!

Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.

All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).


Alex


On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:

just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
n  Sebastian
 
From: Concurrency-interest [[hidden email]] On Behalf Of Alex Otenko
Sent: Thursday, July 06, 2017 10:17 AM
To: Gil Tene
Cc: [hidden email]
Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
 
 
On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:

All it is saying is:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
 
a==b && b==c can be true and can be false
 
It also means that even when:
 
  LocalDateTime d = a;
  ...
  (a == d) may or may not be true. And may change whether it is true or not at any time,
 
I meant an even stronger assertion:
 
assert (a==b) == (b==a) : "No Byzantine optimizations"
assert (a==d) == (a==d): “No Byzantine optimizations"
 
Alex
 


 
 
Alex
 
On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:

Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content. 
There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
.equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
 
For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
  int a = 5;
  int b = 5;
  boolean y = (a == b);  // true
 
For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
  Integer a = new Integer(5);
  Integer b = new Integer(5);
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // false
 
And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // unpredictable, undefined, who knows. 
                                         // Could be true, could be false.
                                         // Could theoretically change the values of a or b, or of something else
 


 
On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:

I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.

While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
For example:
- It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
- It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
- It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
- It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).

So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.

— Gil.

> On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
>
> I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
>
> By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
>
> If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
>
>
> On 2017-07-05 09:20 PM, Gil Tene wrote:
>> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
>> — Gil.
>>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
>>>
>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>> (and related) operations [1].  Using == to compare instances of
>>> value-based classes may lead to "unpredictable results" [2].  Does
>>> this mean I should avoid using compareAndSet with arguments that are
>>> instances of value-based classes?
>>>
>>> It seems like the documentation clearly tells me "yes, avoid doing
>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>> value for example?  Do I have to box the value in something that's not
>>> a value-based class first, like AtomicReference<Box<Instant>>?
>>>
>>> -Michael
>>>
>>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
>>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
 
 

Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
David, the below is a (potentially good) argument for not allowing the creation of subclasses of Object that do not have well defined support identity, identity comparison, identity hashing, or synchronization, since Object supports all those, things that hold Object instances may very well make use of them.

But that horse has long fled the barn. We can argue that value-based classes should not have been specified in Java 8. Or that the future value types should not be derived from Object. But the first case is already in the Java spec, and the second is likely coming (and is sneakily able to use the first as a precedent).

For the "how should we specify things?" discussion, I'm actually squarely on the side of "things with no identity should never have been derived from Object" of this argument. E.g. I would advise other language specifications to avoid making the same mistake, either by not giving the base Object class identity to begin with, or by creating a separate orthogonal type hierarchy for value types and "value based" classes. However, I don't see a way to "fix" the mistake already made, and we have to deal with the language and the machine as spec'ed, not as we wish it were. And so does anyone writing code in the language.

In the context of that reality, we are discussing what correct uses of those new "basterd children of Object" are. And since the basterds clearly have no identity, using any logic that relies on identity behavior in any way is wrong.

Sent from my iPad

On Jul 6, 2017, at 10:53 AM, Gil Tene <[hidden email]> wrote:

Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).

Sent from my iPad

On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email]> wrote:

Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.

List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.

Alex

On 6 Jul 2017, at 17:33, Gil Tene <[hidden email]> wrote:

It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen". 

Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.

For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).

We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.

It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.

For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.

One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...

This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.

Sent from my iPad

On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:

:-) the one causing Byzantine failures!

Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.

All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).


Alex


On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:

just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
n  Sebastian
 
From: Concurrency-interest [[hidden email]] On Behalf Of Alex Otenko
Sent: Thursday, July 06, 2017 10:17 AM
To: Gil Tene
Cc: [hidden email]
Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
 
 
On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:

All it is saying is:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
 
a==b && b==c can be true and can be false
 
It also means that even when:
 
  LocalDateTime d = a;
  ...
  (a == d) may or may not be true. And may change whether it is true or not at any time,
 
I meant an even stronger assertion:
 
assert (a==b) == (b==a) : "No Byzantine optimizations"
assert (a==d) == (a==d): “No Byzantine optimizations"
 
Alex
 


 
 
Alex
 
On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
 


Sent from my iPad


On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:

Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content. 
There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
.equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
 
For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
  int a = 5;
  int b = 5;
  boolean y = (a == b);  // true
 
For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
  Integer a = new Integer(5);
  Integer b = new Integer(5);
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // false
 
And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
 
  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
  boolean x = a.equals(b);   // true
  boolean y = (a == b);   // unpredictable, undefined, who knows. 
                                         // Could be true, could be false.
                                         // Could theoretically change the values of a or b, or of something else
 


 
On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:

I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.

While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
For example:
- It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
- It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
- It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
- It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).

So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.

— Gil.

> On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
>
> I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
>
> By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
>
> If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
>
>
> On 2017-07-05 09:20 PM, Gil Tene wrote:
>> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
>> — Gil.
>>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
>>>
>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>> (and related) operations [1].  Using == to compare instances of
>>> value-based classes may lead to "unpredictable results" [2].  Does
>>> this mean I should avoid using compareAndSet with arguments that are
>>> instances of value-based classes?
>>>
>>> It seems like the documentation clearly tells me "yes, avoid doing
>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>> value for example?  Do I have to box the value in something that's not
>>> a value-based class first, like AtomicReference<Box<Instant>>?
>>>
>>> -Michael
>>>
>>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
>>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
 
 

Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Justin Sampson
In reply to this post by Gil Tene-2
That is absolutely horrifying, and leads me to believe we should not use such "value-based" classes at all in our code. Off I go to find a list of them and forbid them in my codebase. Somehow I thought that I was relatively up-to-date on my Java knowledge and this is the very first time I'm hearing about them. Surely the vast majority of Java programmers are similarly unaware, and the idea that an object instance can actually be replaced by another object instance at runtime is beyond surprising.

-Justin


On 7/6/17, 10:49 AM, "Gil Tene" <[hidden email]> wrote:

    We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.
   
    To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
    - There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
    - Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.
   
    This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).
   
    Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.
   
    In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().
   
    Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().
   
    Sent from my iPad
   
    > On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
    >
    > Howdy,
    >
    > This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
    >
    > It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
    >
    > Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
    >
    > Cheers,
    > Justin
    >
    >
    > On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
    >
    >    Forwarding this reply of mine because I forgot to CC the mailing list.
    >
    >
    >    ---------- Forwarded message ----------
    >    From: Michael Hixson <[hidden email]>
    >    Date: Thu, Jul 6, 2017 at 7:24 AM
    >    Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
    >    value-based classes?
    >    To: Andrew Haley <[hidden email]>
    >
    >
    >>>>    On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
    >>>>> On 06/07/17 11:41, Alex Otenko wrote:
    >>>>
    >>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
    >>>>
    >>>> On 06/07/17 04:59, Michael Hixson wrote:
    >>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
    >>>>> (and related) operations [1].  Using == to compare instances of
    >>>>> value-based classes may lead to "unpredictable results" [2].  Does
    >>>>> this mean I should avoid using compareAndSet with arguments that are
    >>>>> instances of value-based classes?
    >>>>>
    >>>>> It seems like the documentation clearly tells me "yes, avoid doing
    >>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
    >>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
    >>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
    >>>>> value for example?
    >>>>
    >>>> java.time.Instant stores times that are longer than a JVM word, so
    >>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
    >>>> that instances which compare equal also have the property of
    >>>> reference equality.  j.t.Instant factories in the Java library are
    >>>> explicitly documented *not* to have this property, so that doesn't
    >>>> help.
    >>>
    >>> That’s not entirely clear.
    >>>
    >>> Wouldn’t this loop work:
    >>>
    >>> volatile j.t.Instant curr = ...
    >>>
    >>> j.t.Instant next = …
    >>> j.t.Instant tmp = ...
    >>> do {
    >>>  tmp = curr;
    >>>  if (tmp.equal(next)) break;
    >>> } while(!curr.CAS(tmp, next));
    >>>
    >>> // assume curr is equal to next
    >>
    >> Something like that, yes.  But it's going to be evil if there are
    >> several high-frequency writers.  If you're doing all that work in
    >> order to CAS a timestamp, why not use a synchronized block?  It would
    >> at least be less prone to the thundering herd, and we'd generate
    >> pretty decent code for that.  It'd be interesting to compare and
    >> contrast the two approaches for contended and non-contended cases.
    >
    >    The main reason I reached for AtomicReference is that I thought, "I
    >    want thread-safe updates to this read-heavy value where writes won't
    >    get lost if there's contention -- this sounds like the sort of problem
    >    that java.util.concurrent.atomic solves."
    >
    >    As a minor point, I wanted synchronization on reads to be as
    >    minor/invisible as possible, to affect the readers' behavior as little
    >    as possible (in comparison to their behavior when the value they're
    >    reading a constant value with no synchronization).
    >
    >    But if AtomicReference is simply the wrong tool to use here, I
    >    shouldn't use it.  That's fine.
    >
    >>
    >>>> If you want to be able to CAS a reference to a j.t.Instant, you're
    >>>> going to have to wrap accesses to it in a synchronized block.  This is
    >>>> a direct consequence of the JVM's inability to CAS multi-word objects.
    >>>
    >>> This is confusing.
    >>>
    >>> Surely this isn’t talking about CASing a reference? The contents of
    >>> the object can’t be assumed to have any atomicity properties,
    >>> whether it is j.t.Instant or not.
    >>
    >> I agree.  I'm trying to look at what the OP actually wants to do: I
    >> assume this is some kind of atomic timestamp, and the OP wants to be
    >> able to CAS an instance of j.u.Instant.
    >
    >    It was more of a general worry and question.  Should I ever use
    >    AtomicReference with value-based classes?  It sounds like the answer
    >    is no.
    >
    >    But here's some code that illustrates the specific problem I was
    >    trying to solve.  I think it "works" right now, but that it's in
    >    violation of the spec for value-based classes and so possibly not
    >    future-proof, and I think I understand how to fix it now.  Thanks for
    >    the tips.
    >
    >        class MutableClock {
    >
    >            static MutableClock create(Instant instant, ZoneId zone) {
    >                return new MutableClock(
    >                        new AtomicReference<>(instant),
    >                        zone);
    >            }
    >
    >            private final AtomicReference<Instant> instantHolder;
    >            private final ZoneId zone;
    >
    >            private MutableClock(
    >                    AtomicReference<Instant> instantHolder,
    >                    ZoneId zone) {
    >                this.instantHolder = instantHolder;
    >                this.zone = zone;
    >            }
    >
    >            Instant instant() {
    >                return instantHolder.get();
    >            }
    >
    >            ZoneId getZone() {
    >                return zone;
    >            }
    >
    >            void setInstant(Instant newInstant) {
    >                instantHolder.set(newInstant);
    >            }
    >
    >            void add(Duration amountToAdd) {
    >                // this is the part that uses == and CAS
    >                instantHolder.updateAndGet(
    >                      instant -> instant.plus(amountToAdd));
    >            }
    >
    >            MutableClock withZone(ZoneId newZone) {
    >                // conveniently, AtomicReference also acts as a
    >                // vehicle for "shared updates" between instances
    >                // of my class
    >                return new MutableClock(instantHolder, newZone);
    >            }
    >        }
    >
    >    -Michael
    >    _______________________________________________
    >    Concurrency-interest mailing list
    >    [hidden email]
    >    http://cs.oswego.edu/mailman/listinfo/concurrency-interest
    >
    >
    > _______________________________________________
    > Concurrency-interest mailing list
    > [hidden email]
    > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
   

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Brian S O'Neill-3
In reply to this post by Gil Tene-2
Although it would be nice to have value-based classes truly supported,
because the java.time classes are defined as ordinary classes, they can
never change into becoming true value-based classes without breaking
compatibility. You can't just change the definition of instance equality
without completely breaking the language completely. Improper use of a
weak value-based class should at the very least trigger a compiler
warning, but a full runtime check is too extreme.

Consider how these checks are implemented by the compiler. Adding a
runtime check would be equivalent to making every == check, cas, etc
behave like a virtual method call. I wouldn't be terribly happy to see a
performance regression introduced in something so fundamental and used
everywhere.

Also consider problems resulting an exception thrown from the ==
operator. This isn't supposed to happen. Any piece of code which is
designed to be fault tolerant (via exception handling) is now broken,
because it assumed (correctly) that fundamental language design elements
don't change.


On 2017-07-06 11:15 AM, Gil Tene wrote:

> David, the below is a (potentially good) argument for not allowing the
> creation of subclasses of Object that do not have well defined support
> identity, identity comparison, identity hashing, or synchronization,
> since Object supports all those, things that hold Object instances may
> very well make use of them.
>
> But that horse has long fled the barn. We can argue that value-based
> classes should not have been specified in Java 8. Or that the future
> value types should not be derived from Object. But the first case is
> already in the Java spec, and the second is likely coming (and is
> sneakily able to use the first as a precedent).
>
> For the "how should we specify things?" discussion, I'm actually
> squarely on the side of "things with no identity should never have been
> derived from Object" of this argument. E.g. I would advise other
> language specifications to avoid making the same mistake, either by not
> giving the base Object class identity to begin with, or by creating a
> separate orthogonal type hierarchy for value types and "value based"
> classes. However, I don't see a way to "fix" the mistake already made,
> and we have to deal with the language and the machine as spec'ed, not as
> we wish it were. And so does anyone writing code in the language.
>
> In the context of that reality, we are discussing what correct uses of
> those new "basterd children of Object" are. And since the basterds
> clearly have no identity, using any logic that relies on identity
> behavior in any way is wrong.
>
> Sent from my iPad
>
> On Jul 6, 2017, at 10:53 AM, Gil Tene <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>> Hence my suggestion that identity-based operations on instances of
>> value-based classes should throw exceptions... Right now they silently
>> do unpredictable things, and should be avoided in any case (but harder
>> to know/find when you accidentally use them).
>>
>> Sent from my iPad
>>
>> On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email]
>> <mailto:[hidden email]>> wrote:
>>
>>> Are they subclasses of Object or not? If they are not, no questions.
>>> If they are, someone still needs to explain how exactly the “identity
>>> based operations” can be avoided safely.
>>>
>>> List<j.u.Optional> is just a List underneath, and searching for an
>>> item may use “identity based operations”, whether you want it or not
>>> - depending on what implementation of List you happen to use.
>>>
>>> Alex
>>>
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Justin Sampson
The "it's not as horrifying as you might think" crowd (which I'm not sure I'm part of or not) would argue that the worries are overblown. Yes, one "instance" can be freely replaced by another at any point, without you knowing about it. But why would you care? Howe would you be able to tell? If you properly avoid using identity operations (which you were told not to), where is the problem? The objects are immutable, so proper equality testing will never get you the "wrong" logical behavior.

The answer to this is generally "But… concurrency!". Which is why this is an ok place to chat about it probably. With no identity, how do you achieve atomic updates? Michael's MutableClock example (scroll down) of wanting to (potentially concurrently) add duration amounts to some notion of a point in time, while avoiding the potential for "losing" an add racy situations, requires some sort of synchronization. Since Instant is not mutable, and we are necessarily trying to atomically replace one Instant value with another, we have a problem with the notion that these values have no identity (and therefore no way to do a proper CAS on). We are also specifically admonished to not do any synchronization on "instances" of such classes, which should serious dissuade one from trying. Boxing is *an* answer (put the value in an instance that has a proper identity, and then CAS the identity), but a seemingly unsatisfying one...

— Gil.

> On Jul 6, 2017, at 11:47 AM, Justin Sampson <[hidden email]> wrote:
>
> That is absolutely horrifying, and leads me to believe we should not use such "value-based" classes at all in our code. Off I go to find a list of them and forbid them in my codebase. Somehow I thought that I was relatively up-to-date on my Java knowledge and this is the very first time I'm hearing about them. Surely the vast majority of Java programmers are similarly unaware, and the idea that an object instance can actually be replaced by another object instance at runtime is beyond surprising.
>
> -Justin
>
>
> On 7/6/17, 10:49 AM, "Gil Tene" <[hidden email]> wrote:
>
>    We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.
>
>    To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
>    - There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
>    - Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.
>
>    This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).
>
>    Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.
>
>    In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().
>
>    Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().
>
>    Sent from my iPad
>
>> On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
>>
>> Howdy,
>>
>> This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
>>
>> It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
>>
>> Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
>>
>> Cheers,
>> Justin
>>
>>
>> On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
>>
>>   Forwarding this reply of mine because I forgot to CC the mailing list.
>>
>>
>>   ---------- Forwarded message ----------
>>   From: Michael Hixson <[hidden email]>
>>   Date: Thu, Jul 6, 2017 at 7:24 AM
>>   Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
>>   value-based classes?
>>   To: Andrew Haley <[hidden email]>
>>
>>
>>>>>   On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
>>>>>> On 06/07/17 11:41, Alex Otenko wrote:
>>>>>
>>>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
>>>>>
>>>>> On 06/07/17 04:59, Michael Hixson wrote:
>>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>>> (and related) operations [1].  Using == to compare instances of
>>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>>> instances of value-based classes?
>>>>>>
>>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>>> value for example?
>>>>>
>>>>> java.time.Instant stores times that are longer than a JVM word, so
>>>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>>>>> that instances which compare equal also have the property of
>>>>> reference equality.  j.t.Instant factories in the Java library are
>>>>> explicitly documented *not* to have this property, so that doesn't
>>>>> help.
>>>>
>>>> That’s not entirely clear.
>>>>
>>>> Wouldn’t this loop work:
>>>>
>>>> volatile j.t.Instant curr = ...
>>>>
>>>> j.t.Instant next = …
>>>> j.t.Instant tmp = ...
>>>> do {
>>>> tmp = curr;
>>>> if (tmp.equal(next)) break;
>>>> } while(!curr.CAS(tmp, next));
>>>>
>>>> // assume curr is equal to next
>>>
>>> Something like that, yes.  But it's going to be evil if there are
>>> several high-frequency writers.  If you're doing all that work in
>>> order to CAS a timestamp, why not use a synchronized block?  It would
>>> at least be less prone to the thundering herd, and we'd generate
>>> pretty decent code for that.  It'd be interesting to compare and
>>> contrast the two approaches for contended and non-contended cases.
>>
>>   The main reason I reached for AtomicReference is that I thought, "I
>>   want thread-safe updates to this read-heavy value where writes won't
>>   get lost if there's contention -- this sounds like the sort of problem
>>   that java.util.concurrent.atomic solves."
>>
>>   As a minor point, I wanted synchronization on reads to be as
>>   minor/invisible as possible, to affect the readers' behavior as little
>>   as possible (in comparison to their behavior when the value they're
>>   reading a constant value with no synchronization).
>>
>>   But if AtomicReference is simply the wrong tool to use here, I
>>   shouldn't use it.  That's fine.
>>
>>>
>>>>> If you want to be able to CAS a reference to a j.t.Instant, you're
>>>>> going to have to wrap accesses to it in a synchronized block.  This is
>>>>> a direct consequence of the JVM's inability to CAS multi-word objects.
>>>>
>>>> This is confusing.
>>>>
>>>> Surely this isn’t talking about CASing a reference? The contents of
>>>> the object can’t be assumed to have any atomicity properties,
>>>> whether it is j.t.Instant or not.
>>>
>>> I agree.  I'm trying to look at what the OP actually wants to do: I
>>> assume this is some kind of atomic timestamp, and the OP wants to be
>>> able to CAS an instance of j.u.Instant.
>>
>>   It was more of a general worry and question.  Should I ever use
>>   AtomicReference with value-based classes?  It sounds like the answer
>>   is no.
>>
>>   But here's some code that illustrates the specific problem I was
>>   trying to solve.  I think it "works" right now, but that it's in
>>   violation of the spec for value-based classes and so possibly not
>>   future-proof, and I think I understand how to fix it now.  Thanks for
>>   the tips.
>>
>>       class MutableClock {
>>
>>           static MutableClock create(Instant instant, ZoneId zone) {
>>               return new MutableClock(
>>                       new AtomicReference<>(instant),
>>                       zone);
>>           }
>>
>>           private final AtomicReference<Instant> instantHolder;
>>           private final ZoneId zone;
>>
>>           private MutableClock(
>>                   AtomicReference<Instant> instantHolder,
>>                   ZoneId zone) {
>>               this.instantHolder = instantHolder;
>>               this.zone = zone;
>>           }
>>
>>           Instant instant() {
>>               return instantHolder.get();
>>           }
>>
>>           ZoneId getZone() {
>>               return zone;
>>           }
>>
>>           void setInstant(Instant newInstant) {
>>               instantHolder.set(newInstant);
>>           }
>>
>>           void add(Duration amountToAdd) {
>>               // this is the part that uses == and CAS
>>               instantHolder.updateAndGet(
>>                     instant -> instant.plus(amountToAdd));
>>           }
>>
>>           MutableClock withZone(ZoneId newZone) {
>>               // conveniently, AtomicReference also acts as a
>>               // vehicle for "shared updates" between instances
>>               // of my class
>>               return new MutableClock(instantHolder, newZone);
>>           }
>>       }
>>
>>   -Michael
>>   _______________________________________________
>>   Concurrency-interest mailing list
>>   [hidden email]
>>   http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Kirk Pepperdine
I think this is horrifying. One of the guarantees of these types of systems is a notion of identity and singularity which ensures consistency in the runtime. This one of the things I liked about value types. It gave a stronger sense of singularity but now as I understand this, singularity is no longer guaranteed which means you need to do extra stuff to ensure consistency. This brings us smack into the problems with O/R mapping (inject and maintenance of foreign key to ensure singularity and consistency).

I do hope I’ve misunderstood this whole thread.

Regards,
Kirk

> On Jul 6, 2017, at 9:12 PM, Gil Tene <[hidden email]> wrote:
>
> The "it's not as horrifying as you might think" crowd (which I'm not sure I'm part of or not) would argue that the worries are overblown. Yes, one "instance" can be freely replaced by another at any point, without you knowing about it. But why would you care? Howe would you be able to tell? If you properly avoid using identity operations (which you were told not to), where is the problem? The objects are immutable, so proper equality testing will never get you the "wrong" logical behavior.
>
> The answer to this is generally "But… concurrency!". Which is why this is an ok place to chat about it probably. With no identity, how do you achieve atomic updates? Michael's MutableClock example (scroll down) of wanting to (potentially concurrently) add duration amounts to some notion of a point in time, while avoiding the potential for "losing" an add racy situations, requires some sort of synchronization. Since Instant is not mutable, and we are necessarily trying to atomically replace one Instant value with another, we have a problem with the notion that these values have no identity (and therefore no way to do a proper CAS on). We are also specifically admonished to not do any synchronization on "instances" of such classes, which should serious dissuade one from trying. Boxing is *an* answer (put the value in an instance that has a proper identity, and then CAS the identity), but a seemingly unsatisfying one...
>
> — Gil.
>
>> On Jul 6, 2017, at 11:47 AM, Justin Sampson <[hidden email]> wrote:
>>
>> That is absolutely horrifying, and leads me to believe we should not use such "value-based" classes at all in our code. Off I go to find a list of them and forbid them in my codebase. Somehow I thought that I was relatively up-to-date on my Java knowledge and this is the very first time I'm hearing about them. Surely the vast majority of Java programmers are similarly unaware, and the idea that an object instance can actually be replaced by another object instance at runtime is beyond surprising.
>>
>> -Justin
>>
>>
>> On 7/6/17, 10:49 AM, "Gil Tene" <[hidden email]> wrote:
>>
>>   We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.
>>
>>   To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
>>   - There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
>>   - Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.
>>
>>   This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).
>>
>>   Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.
>>
>>   In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().
>>
>>   Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().
>>
>>   Sent from my iPad
>>
>>> On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
>>>
>>> Howdy,
>>>
>>> This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
>>>
>>> It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
>>>
>>> Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
>>>
>>> Cheers,
>>> Justin
>>>
>>>
>>> On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
>>>
>>>  Forwarding this reply of mine because I forgot to CC the mailing list.
>>>
>>>
>>>  ---------- Forwarded message ----------
>>>  From: Michael Hixson <[hidden email]>
>>>  Date: Thu, Jul 6, 2017 at 7:24 AM
>>>  Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
>>>  value-based classes?
>>>  To: Andrew Haley <[hidden email]>
>>>
>>>
>>>>>>  On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
>>>>>>> On 06/07/17 11:41, Alex Otenko wrote:
>>>>>>
>>>>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
>>>>>>
>>>>>> On 06/07/17 04:59, Michael Hixson wrote:
>>>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>>>> (and related) operations [1].  Using == to compare instances of
>>>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>>>> instances of value-based classes?
>>>>>>>
>>>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>>>> value for example?
>>>>>>
>>>>>> java.time.Instant stores times that are longer than a JVM word, so
>>>>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>>>>>> that instances which compare equal also have the property of
>>>>>> reference equality.  j.t.Instant factories in the Java library are
>>>>>> explicitly documented *not* to have this property, so that doesn't
>>>>>> help.
>>>>>
>>>>> That’s not entirely clear.
>>>>>
>>>>> Wouldn’t this loop work:
>>>>>
>>>>> volatile j.t.Instant curr = ...
>>>>>
>>>>> j.t.Instant next = …
>>>>> j.t.Instant tmp = ...
>>>>> do {
>>>>> tmp = curr;
>>>>> if (tmp.equal(next)) break;
>>>>> } while(!curr.CAS(tmp, next));
>>>>>
>>>>> // assume curr is equal to next
>>>>
>>>> Something like that, yes.  But it's going to be evil if there are
>>>> several high-frequency writers.  If you're doing all that work in
>>>> order to CAS a timestamp, why not use a synchronized block?  It would
>>>> at least be less prone to the thundering herd, and we'd generate
>>>> pretty decent code for that.  It'd be interesting to compare and
>>>> contrast the two approaches for contended and non-contended cases.
>>>
>>>  The main reason I reached for AtomicReference is that I thought, "I
>>>  want thread-safe updates to this read-heavy value where writes won't
>>>  get lost if there's contention -- this sounds like the sort of problem
>>>  that java.util.concurrent.atomic solves."
>>>
>>>  As a minor point, I wanted synchronization on reads to be as
>>>  minor/invisible as possible, to affect the readers' behavior as little
>>>  as possible (in comparison to their behavior when the value they're
>>>  reading a constant value with no synchronization).
>>>
>>>  But if AtomicReference is simply the wrong tool to use here, I
>>>  shouldn't use it.  That's fine.
>>>
>>>>
>>>>>> If you want to be able to CAS a reference to a j.t.Instant, you're
>>>>>> going to have to wrap accesses to it in a synchronized block.  This is
>>>>>> a direct consequence of the JVM's inability to CAS multi-word objects.
>>>>>
>>>>> This is confusing.
>>>>>
>>>>> Surely this isn’t talking about CASing a reference? The contents of
>>>>> the object can’t be assumed to have any atomicity properties,
>>>>> whether it is j.t.Instant or not.
>>>>
>>>> I agree.  I'm trying to look at what the OP actually wants to do: I
>>>> assume this is some kind of atomic timestamp, and the OP wants to be
>>>> able to CAS an instance of j.u.Instant.
>>>
>>>  It was more of a general worry and question.  Should I ever use
>>>  AtomicReference with value-based classes?  It sounds like the answer
>>>  is no.
>>>
>>>  But here's some code that illustrates the specific problem I was
>>>  trying to solve.  I think it "works" right now, but that it's in
>>>  violation of the spec for value-based classes and so possibly not
>>>  future-proof, and I think I understand how to fix it now.  Thanks for
>>>  the tips.
>>>
>>>      class MutableClock {
>>>
>>>          static MutableClock create(Instant instant, ZoneId zone) {
>>>              return new MutableClock(
>>>                      new AtomicReference<>(instant),
>>>                      zone);
>>>          }
>>>
>>>          private final AtomicReference<Instant> instantHolder;
>>>          private final ZoneId zone;
>>>
>>>          private MutableClock(
>>>                  AtomicReference<Instant> instantHolder,
>>>                  ZoneId zone) {
>>>              this.instantHolder = instantHolder;
>>>              this.zone = zone;
>>>          }
>>>
>>>          Instant instant() {
>>>              return instantHolder.get();
>>>          }
>>>
>>>          ZoneId getZone() {
>>>              return zone;
>>>          }
>>>
>>>          void setInstant(Instant newInstant) {
>>>              instantHolder.set(newInstant);
>>>          }
>>>
>>>          void add(Duration amountToAdd) {
>>>              // this is the part that uses == and CAS
>>>              instantHolder.updateAndGet(
>>>                    instant -> instant.plus(amountToAdd));
>>>          }
>>>
>>>          MutableClock withZone(ZoneId newZone) {
>>>              // conveniently, AtomicReference also acts as a
>>>              // vehicle for "shared updates" between instances
>>>              // of my class
>>>              return new MutableClock(instantHolder, newZone);
>>>          }
>>>      }
>>>
>>>  -Michael
>>>  _______________________________________________
>>>  Concurrency-interest mailing list
>>>  [hidden email]
>>>  http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>
>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> [hidden email]
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Brian S O'Neill-3
I think that performant runtime checks can be added. When you haven't stuffed indentity-lacking things into other things that explore identity, things will be just as fast. When you do, they will blow up, and speed won't matter.

The larger problem of "surprising behavior" when passing a non-identity-capable thing (basterd child of Object) to some thing that expects Object and does object things with it at some future point in time (like maybe using identity for something) is likely to come at us hard when "codes like a class, works like an int" value types are introduced. IMO, it is "hard" (as in impractical) to compile-time check this stuff away completely. You can cover some (many?) cases, but runtime issues will always remain. The situation where people are appalled at what can happen with instances of value-based classes that they may pass to innocent Object-expecting things is just a glimpse of the future. IMO an exception is the least bad thing you can do to them. Much better than letting their code run.

— Gil.

> On Jul 6, 2017, at 11:52 AM, Brian S O'Neill <[hidden email]> wrote:
>
> Although it would be nice to have value-based classes truly supported, because the java.time classes are defined as ordinary classes, they can never change into becoming true value-based classes without breaking compatibility. You can't just change the definition of instance equality without completely breaking the language completely. Improper use of a weak value-based class should at the very least trigger a compiler warning, but a full runtime check is too extreme.
>
> Consider how these checks are implemented by the compiler. Adding a runtime check would be equivalent to making every == check, cas, etc behave like a virtual method call. I wouldn't be terribly happy to see a performance regression introduced in something so fundamental and used everywhere.
>
> Also consider problems resulting an exception thrown from the == operator. This isn't supposed to happen. Any piece of code which is designed to be fault tolerant (via exception handling) is now broken, because it assumed (correctly) that fundamental language design elements don't change.
>
>
> On 2017-07-06 11:15 AM, Gil Tene wrote:
>> David, the below is a (potentially good) argument for not allowing the creation of subclasses of Object that do not have well defined support identity, identity comparison, identity hashing, or synchronization, since Object supports all those, things that hold Object instances may very well make use of them.
>> But that horse has long fled the barn. We can argue that value-based classes should not have been specified in Java 8. Or that the future value types should not be derived from Object. But the first case is already in the Java spec, and the second is likely coming (and is sneakily able to use the first as a precedent).
>> For the "how should we specify things?" discussion, I'm actually squarely on the side of "things with no identity should never have been derived from Object" of this argument. E.g. I would advise other language specifications to avoid making the same mistake, either by not giving the base Object class identity to begin with, or by creating a separate orthogonal type hierarchy for value types and "value based" classes. However, I don't see a way to "fix" the mistake already made, and we have to deal with the language and the machine as spec'ed, not as we wish it were. And so does anyone writing code in the language.
>> In the context of that reality, we are discussing what correct uses of those new "basterd children of Object" are. And since the basterds clearly have no identity, using any logic that relies on identity behavior in any way is wrong.
>> Sent from my iPad
>> On Jul 6, 2017, at 10:53 AM, Gil Tene <[hidden email] <mailto:[hidden email]>> wrote:
>>> Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).
>>>
>>> Sent from my iPad
>>>
>>> On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email] <mailto:[hidden email]>> wrote:
>>>
>>>> Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.
>>>>
>>>> List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.
>>>>
>>>> Alex
>>>>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Alex Otenko
In reply to this post by Gil Tene-2
:-) It’s NaN, but for the objects.

Using “equals” is just as ugly. It has completely different semantics.

equality
equivalence
homotopy

all talk about sameness of things. I would tell the “it’s not as horrifying” crowd that it is absolutely wrong to force me to use equivalence where I mean equality. That’s the horrifying thing.

It’s not “more correct” to use “equals()” instead of “==“. Because it is not an optimisation, it just has a different meaning. Optional(x).equals(Optional(y)), if x.equals(y), but it doesn’t mean I don’t care which one is referenced - exactly because x and y do have identities.


There is sense in having a concept of a class whose objects convey no meaning except the existence of extra structure with its own virtual method table around some other values. But language needs support for safe use of them.


Alex

> On 6 Jul 2017, at 20:12, Gil Tene <[hidden email]> wrote:
>
> The "it's not as horrifying as you might think" crowd (which I'm not sure I'm part of or not) would argue that the worries are overblown. Yes, one "instance" can be freely replaced by another at any point, without you knowing about it. But why would you care? Howe would you be able to tell? If you properly avoid using identity operations (which you were told not to), where is the problem? The objects are immutable, so proper equality testing will never get you the "wrong" logical behavior.
>
> The answer to this is generally "But… concurrency!". Which is why this is an ok place to chat about it probably. With no identity, how do you achieve atomic updates? Michael's MutableClock example (scroll down) of wanting to (potentially concurrently) add duration amounts to some notion of a point in time, while avoiding the potential for "losing" an add racy situations, requires some sort of synchronization. Since Instant is not mutable, and we are necessarily trying to atomically replace one Instant value with another, we have a problem with the notion that these values have no identity (and therefore no way to do a proper CAS on). We are also specifically admonished to not do any synchronization on "instances" of such classes, which should serious dissuade one from trying. Boxing is *an* answer (put the value in an instance that has a proper identity, and then CAS the identity), but a seemingly unsatisfying one...
>
> — Gil.
>
>> On Jul 6, 2017, at 11:47 AM, Justin Sampson <[hidden email]> wrote:
>>
>> That is absolutely horrifying, and leads me to believe we should not use such "value-based" classes at all in our code. Off I go to find a list of them and forbid them in my codebase. Somehow I thought that I was relatively up-to-date on my Java knowledge and this is the very first time I'm hearing about them. Surely the vast majority of Java programmers are similarly unaware, and the idea that an object instance can actually be replaced by another object instance at runtime is beyond surprising.
>>
>> -Justin
>>
>>
>> On 7/6/17, 10:49 AM, "Gil Tene" <[hidden email]> wrote:
>>
>>   We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.
>>
>>   To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
>>   - There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
>>   - Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.
>>
>>   This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).
>>
>>   Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.
>>
>>   In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().
>>
>>   Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().
>>
>>   Sent from my iPad
>>
>>> On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
>>>
>>> Howdy,
>>>
>>> This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
>>>
>>> It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
>>>
>>> Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
>>>
>>> Cheers,
>>> Justin
>>>
>>>
>>> On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
>>>
>>>  Forwarding this reply of mine because I forgot to CC the mailing list.
>>>
>>>
>>>  ---------- Forwarded message ----------
>>>  From: Michael Hixson <[hidden email]>
>>>  Date: Thu, Jul 6, 2017 at 7:24 AM
>>>  Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
>>>  value-based classes?
>>>  To: Andrew Haley <[hidden email]>
>>>
>>>
>>>>>>  On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
>>>>>>> On 06/07/17 11:41, Alex Otenko wrote:
>>>>>>
>>>>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
>>>>>>
>>>>>> On 06/07/17 04:59, Michael Hixson wrote:
>>>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>>>> (and related) operations [1].  Using == to compare instances of
>>>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>>>> instances of value-based classes?
>>>>>>>
>>>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>>>> value for example?
>>>>>>
>>>>>> java.time.Instant stores times that are longer than a JVM word, so
>>>>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>>>>>> that instances which compare equal also have the property of
>>>>>> reference equality.  j.t.Instant factories in the Java library are
>>>>>> explicitly documented *not* to have this property, so that doesn't
>>>>>> help.
>>>>>
>>>>> That’s not entirely clear.
>>>>>
>>>>> Wouldn’t this loop work:
>>>>>
>>>>> volatile j.t.Instant curr = ...
>>>>>
>>>>> j.t.Instant next = …
>>>>> j.t.Instant tmp = ...
>>>>> do {
>>>>> tmp = curr;
>>>>> if (tmp.equal(next)) break;
>>>>> } while(!curr.CAS(tmp, next));
>>>>>
>>>>> // assume curr is equal to next
>>>>
>>>> Something like that, yes.  But it's going to be evil if there are
>>>> several high-frequency writers.  If you're doing all that work in
>>>> order to CAS a timestamp, why not use a synchronized block?  It would
>>>> at least be less prone to the thundering herd, and we'd generate
>>>> pretty decent code for that.  It'd be interesting to compare and
>>>> contrast the two approaches for contended and non-contended cases.
>>>
>>>  The main reason I reached for AtomicReference is that I thought, "I
>>>  want thread-safe updates to this read-heavy value where writes won't
>>>  get lost if there's contention -- this sounds like the sort of problem
>>>  that java.util.concurrent.atomic solves."
>>>
>>>  As a minor point, I wanted synchronization on reads to be as
>>>  minor/invisible as possible, to affect the readers' behavior as little
>>>  as possible (in comparison to their behavior when the value they're
>>>  reading a constant value with no synchronization).
>>>
>>>  But if AtomicReference is simply the wrong tool to use here, I
>>>  shouldn't use it.  That's fine.
>>>
>>>>
>>>>>> If you want to be able to CAS a reference to a j.t.Instant, you're
>>>>>> going to have to wrap accesses to it in a synchronized block.  This is
>>>>>> a direct consequence of the JVM's inability to CAS multi-word objects.
>>>>>
>>>>> This is confusing.
>>>>>
>>>>> Surely this isn’t talking about CASing a reference? The contents of
>>>>> the object can’t be assumed to have any atomicity properties,
>>>>> whether it is j.t.Instant or not.
>>>>
>>>> I agree.  I'm trying to look at what the OP actually wants to do: I
>>>> assume this is some kind of atomic timestamp, and the OP wants to be
>>>> able to CAS an instance of j.u.Instant.
>>>
>>>  It was more of a general worry and question.  Should I ever use
>>>  AtomicReference with value-based classes?  It sounds like the answer
>>>  is no.
>>>
>>>  But here's some code that illustrates the specific problem I was
>>>  trying to solve.  I think it "works" right now, but that it's in
>>>  violation of the spec for value-based classes and so possibly not
>>>  future-proof, and I think I understand how to fix it now.  Thanks for
>>>  the tips.
>>>
>>>      class MutableClock {
>>>
>>>          static MutableClock create(Instant instant, ZoneId zone) {
>>>              return new MutableClock(
>>>                      new AtomicReference<>(instant),
>>>                      zone);
>>>          }
>>>
>>>          private final AtomicReference<Instant> instantHolder;
>>>          private final ZoneId zone;
>>>
>>>          private MutableClock(
>>>                  AtomicReference<Instant> instantHolder,
>>>                  ZoneId zone) {
>>>              this.instantHolder = instantHolder;
>>>              this.zone = zone;
>>>          }
>>>
>>>          Instant instant() {
>>>              return instantHolder.get();
>>>          }
>>>
>>>          ZoneId getZone() {
>>>              return zone;
>>>          }
>>>
>>>          void setInstant(Instant newInstant) {
>>>              instantHolder.set(newInstant);
>>>          }
>>>
>>>          void add(Duration amountToAdd) {
>>>              // this is the part that uses == and CAS
>>>              instantHolder.updateAndGet(
>>>                    instant -> instant.plus(amountToAdd));
>>>          }
>>>
>>>          MutableClock withZone(ZoneId newZone) {
>>>              // conveniently, AtomicReference also acts as a
>>>              // vehicle for "shared updates" between instances
>>>              // of my class
>>>              return new MutableClock(instantHolder, newZone);
>>>          }
>>>      }
>>>
>>>  -Michael
>>>  _______________________________________________
>>>  Concurrency-interest mailing list
>>>  [hidden email]
>>>  http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>
>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> [hidden email]
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Alex Otenko
In reply to this post by Gil Tene-2
What’s wrong with “==“ doing a sensible default thing? Like, bitwise compare the “contents”? It’s certainly no slower than calling equals() that perhaps will do more than just bitwise-compare.

What’s wrong with identityHashCode producing a code based on identityHashCodes of the “contents”, or the bit contents of the primitive members?

Alex

> On 6 Jul 2017, at 20:23, Gil Tene <[hidden email]> wrote:
>
> I think that performant runtime checks can be added. When you haven't stuffed indentity-lacking things into other things that explore identity, things will be just as fast. When you do, they will blow up, and speed won't matter.
>
> The larger problem of "surprising behavior" when passing a non-identity-capable thing (basterd child of Object) to some thing that expects Object and does object things with it at some future point in time (like maybe using identity for something) is likely to come at us hard when "codes like a class, works like an int" value types are introduced. IMO, it is "hard" (as in impractical) to compile-time check this stuff away completely. You can cover some (many?) cases, but runtime issues will always remain. The situation where people are appalled at what can happen with instances of value-based classes that they may pass to innocent Object-expecting things is just a glimpse of the future. IMO an exception is the least bad thing you can do to them. Much better than letting their code run.
>
> — Gil.
>
>> On Jul 6, 2017, at 11:52 AM, Brian S O'Neill <[hidden email]> wrote:
>>
>> Although it would be nice to have value-based classes truly supported, because the java.time classes are defined as ordinary classes, they can never change into becoming true value-based classes without breaking compatibility. You can't just change the definition of instance equality without completely breaking the language completely. Improper use of a weak value-based class should at the very least trigger a compiler warning, but a full runtime check is too extreme.
>>
>> Consider how these checks are implemented by the compiler. Adding a runtime check would be equivalent to making every == check, cas, etc behave like a virtual method call. I wouldn't be terribly happy to see a performance regression introduced in something so fundamental and used everywhere.
>>
>> Also consider problems resulting an exception thrown from the == operator. This isn't supposed to happen. Any piece of code which is designed to be fault tolerant (via exception handling) is now broken, because it assumed (correctly) that fundamental language design elements don't change.
>>
>>
>> On 2017-07-06 11:15 AM, Gil Tene wrote:
>>> David, the below is a (potentially good) argument for not allowing the creation of subclasses of Object that do not have well defined support identity, identity comparison, identity hashing, or synchronization, since Object supports all those, things that hold Object instances may very well make use of them.
>>> But that horse has long fled the barn. We can argue that value-based classes should not have been specified in Java 8. Or that the future value types should not be derived from Object. But the first case is already in the Java spec, and the second is likely coming (and is sneakily able to use the first as a precedent).
>>> For the "how should we specify things?" discussion, I'm actually squarely on the side of "things with no identity should never have been derived from Object" of this argument. E.g. I would advise other language specifications to avoid making the same mistake, either by not giving the base Object class identity to begin with, or by creating a separate orthogonal type hierarchy for value types and "value based" classes. However, I don't see a way to "fix" the mistake already made, and we have to deal with the language and the machine as spec'ed, not as we wish it were. And so does anyone writing code in the language.
>>> In the context of that reality, we are discussing what correct uses of those new "basterd children of Object" are. And since the basterds clearly have no identity, using any logic that relies on identity behavior in any way is wrong.
>>> Sent from my iPad
>>> On Jul 6, 2017, at 10:53 AM, Gil Tene <[hidden email] <mailto:[hidden email]>> wrote:
>>>> Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).
>>>>
>>>> Sent from my iPad
>>>>
>>>> On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email] <mailto:[hidden email]>> wrote:
>>>>
>>>>> Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.
>>>>>
>>>>> List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.
>>>>>
>>>>> Alex
>>>>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Fwd: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Alex Otenko

> On Jul 6, 2017, at 1:09 PM, Alex Otenko <[hidden email]> wrote:
>
> :-) It’s NaN, but for the objects.
>

Well put. And a very good analogy. The identity of an instance of a value-based classes may act like a NaN at any time. And x == x is false when x is a NaN...

> Using “equals” is just as ugly. It has completely different semantics.


>
> equality
> equivalence
> homotopy

And == for objects (which means "same identity") is [I believe] different from all of the above.

Alas, we don't have a well established meaning for .equivalent() in Java.

>
> all talk about sameness of things. I would tell the “it’s not as horrifying” crowd that it is absolutely wrong to force me to use equivalence where I mean equality. That’s the horrifying thing.
>
> It’s not “more correct” to use “equals()” instead of “==“. Because it is not an optimisation, it just has a different meaning. Optional(x).equals(Optional(y)), if x.equals(y), but it doesn’t mean I don’t care which one is referenced - exactly because x and y do have identities.

Agreed.

Alas, being immutable and non-constrictble (created only by factories) doesn't actually mean non-null everywhere… Super-annoyingly, it is perfectly "valid" (as in will compile and run something) to pass a null argument when an Optional is expected…

Interesting mention of "nullability": http://mail.openjdk.java.net/pipermail/valhalla-dev/2015-January/000555.html , and a discussion of the subject in general (with some good links) here: https://blog.codefx.org/java/value-based-classes/ . I especially like the specific quotes from sources:

-  "Optional is new, and the disclaimers arrived on day 1. Integer, on the other hand, is probably hopelessly polluted, and I am sure that it would break gobs of important code if Integer ceased to be lockable (despite what we may think of such a practice.)"

- "In Java 8 value types are preceded by value-based classes. Their precise relation in the future is unclear but it could be similar to that of boxed and unboxed primitives (e.g. Integer and  int). Additionally, the compiler will likely be free to silently switch between the two to improve performance. Exactly that switching back and forth, i.e. removing and later recreating a reference, also forbids identity-based mechanisms to be applied to value-based classes."

removing and later recreating a reference…. That's certainly in the cars.


>
>
> There is sense in having a concept of a class whose objects convey no meaning except the existence of extra structure with its own virtual method table around some other values. But language needs support for safe use of them.
>
>
> Alex
>
>> On 6 Jul 2017, at 20:12, Gil Tene <[hidden email]> wrote:
>>
>> The "it's not as horrifying as you might think" crowd (which I'm not sure I'm part of or not) would argue that the worries are overblown. Yes, one "instance" can be freely replaced by another at any point, without you knowing about it. But why would you care? Howe would you be able to tell? If you properly avoid using identity operations (which you were told not to), where is the problem? The objects are immutable, so proper equality testing will never get you the "wrong" logical behavior.
>>
>> The answer to this is generally "But… concurrency!". Which is why this is an ok place to chat about it probably. With no identity, how do you achieve atomic updates? Michael's MutableClock example (scroll down) of wanting to (potentially concurrently) add duration amounts to some notion of a point in time, while avoiding the potential for "losing" an add racy situations, requires some sort of synchronization. Since Instant is not mutable, and we are necessarily trying to atomically replace one Instant value with another, we have a problem with the notion that these values have no identity (and therefore no way to do a proper CAS on). We are also specifically admonished to not do any synchronization on "instances" of such classes, which should serious dissuade one from trying. Boxing is *an* answer (put the value in an instance that has a proper identity, and then CAS the identity), but a seemingly unsatisfying one...
>>
>> — Gil.
>>
>>> On Jul 6, 2017, at 11:47 AM, Justin Sampson <[hidden email]> wrote:
>>>
>>> That is absolutely horrifying, and leads me to believe we should not use such "value-based" classes at all in our code. Off I go to find a list of them and forbid them in my codebase. Somehow I thought that I was relatively up-to-date on my Java knowledge and this is the very first time I'm hearing about them. Surely the vast majority of Java programmers are similarly unaware, and the idea that an object instance can actually be replaced by another object instance at runtime is beyond surprising.
>>>
>>> -Justin
>>>
>>>
>>> On 7/6/17, 10:49 AM, "Gil Tene" <[hidden email]> wrote:
>>>
>>>  We are not discussing the upcoming value types. We are discussing the value-based classes as currently spec'ed in Java SE 8. Instant is a good example of such a class.
>>>
>>>  To give you a feel for a currently valid (and may soon occur) optimization in Java 8: The current spec'ed behavior for Instant makes it possible to "inline" instances of Instant into their containing objects (which refer to them with mutable fields):
>>>  - There are no valid identity operations on Instant, so assignment can be validly done by copying contents onto the inlined version. A "get" of an inlined instance (where it can't be escape analyzed away) can be performed by returning a new (and different) instance of Instant.
>>>  - Word-tearing on value assignment [e.g. myClock.setInstsnt(Instant.now()))] can be avoided at least on some platforms, e.g. with 16-byte atomic operations, where the state of Instant instances can be represented in 16 bytes or less.
>>>
>>>  This can then result in an elimination of a dereferencing operation when e.g. accessing someClock.getInstant().getNano(). (and no new instance will be created).
>>>
>>>  Now the specific generics based containment below [AtomicReference<Instant>] may seem a bit more "challenging" (and likely will happen much later than in the non generic cases), but given the fact that the AtomicReference instance use is local to the MutableClock class and private, and no instances of that AtomicReference are exposed elsewhere, it would be valid to transform this code to use some custom subclass of AtomicReference that had  an Instant instance inlined in it. At that point, the updateAndGet operation comes into play. It may have "interesting" behavior because it is identity based, or (more likely) its existence could just prevent the whole optimization from occurring.
>>>
>>>  In any case, to keep to well specified behavior, I'd box the Instant when putting it in an AtomicReference. That will provide you with a safe concurrent add() that doesn't use identity on Instant. You can probably do some simple caching on the get for speed (hold a cachedInstant field and a valid flag, re-read from boxed contents whenever invalid) with an invalidation (set invalid after each modification of the boxed contents) in set() and add().
>>>
>>>  Oh, and BTW, you should probably check for null and enforce non-null for all incoming Instance arguments, e.g. in the constructor and in setInstance().
>>>
>>>  Sent from my iPad
>>>
>>>> On Jul 6, 2017, at 9:01 AM, Justin Sampson <[hidden email]> wrote:
>>>>
>>>> Howdy,
>>>>
>>>> This thread got sidetracked with discussion of the upcoming "value types" in some later version of the JDK, which don't exist yet in 8, and really aren't relevant at all to Michael's question. He's asking about the existing Instant class, which is simply an immutable object with an equals() that compares its contents.
>>>>
>>>> It's absolutely silly to suggest that AtomicReference "doesn't work" for things like Instant. It simply uses identity instead of equals() in its operations, which is entirely well-defined.
>>>>
>>>> Michael's example MutableClock will work just fine. It uses updateAndGet(), which CAS's the result of the update. The point of the CAS is merely to check whether another thread has updated the reference concurrently, for which identity works correctly. The update is retried if the CAS fails, so there's no problem introduced by the fact that equals() for the value is different from equality.
>>>>
>>>> Cheers,
>>>> Justin
>>>>
>>>>
>>>> On 7/6/17, 7:31 AM, "Concurrency-interest on behalf of Michael Hixson" <[hidden email] on behalf of [hidden email]> wrote:
>>>>
>>>> Forwarding this reply of mine because I forgot to CC the mailing list.
>>>>
>>>>
>>>> ---------- Forwarded message ----------
>>>> From: Michael Hixson <[hidden email]>
>>>> Date: Thu, Jul 6, 2017 at 7:24 AM
>>>> Subject: Re: [concurrency-interest] Should I avoid compareAndSet with
>>>> value-based classes?
>>>> To: Andrew Haley <[hidden email]>
>>>>
>>>>
>>>>>>> On Thu, Jul 6, 2017 at 4:20 AM, Andrew Haley <[hidden email]> wrote:
>>>>>>>> On 06/07/17 11:41, Alex Otenko wrote:
>>>>>>>
>>>>>>> On 6 Jul 2017, at 10:13, Andrew Haley <[hidden email]> wrote:
>>>>>>>
>>>>>>> On 06/07/17 04:59, Michael Hixson wrote:
>>>>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>>>>> (and related) operations [1].  Using == to compare instances of
>>>>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>>>>> instances of value-based classes?
>>>>>>>>
>>>>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>>>>> value for example?
>>>>>>>
>>>>>>> java.time.Instant stores times that are longer than a JVM word, so
>>>>>>> they cannot be CAS'd in a lock-free way unless a factory guarantees
>>>>>>> that instances which compare equal also have the property of
>>>>>>> reference equality.  j.t.Instant factories in the Java library are
>>>>>>> explicitly documented *not* to have this property, so that doesn't
>>>>>>> help.
>>>>>>
>>>>>> That’s not entirely clear.
>>>>>>
>>>>>> Wouldn’t this loop work:
>>>>>>
>>>>>> volatile j.t.Instant curr = ...
>>>>>>
>>>>>> j.t.Instant next = …
>>>>>> j.t.Instant tmp = ...
>>>>>> do {
>>>>>> tmp = curr;
>>>>>> if (tmp.equal(next)) break;
>>>>>> } while(!curr.CAS(tmp, next));
>>>>>>
>>>>>> // assume curr is equal to next
>>>>>
>>>>> Something like that, yes.  But it's going to be evil if there are
>>>>> several high-frequency writers.  If you're doing all that work in
>>>>> order to CAS a timestamp, why not use a synchronized block?  It would
>>>>> at least be less prone to the thundering herd, and we'd generate
>>>>> pretty decent code for that.  It'd be interesting to compare and
>>>>> contrast the two approaches for contended and non-contended cases.
>>>>
>>>> The main reason I reached for AtomicReference is that I thought, "I
>>>> want thread-safe updates to this read-heavy value where writes won't
>>>> get lost if there's contention -- this sounds like the sort of problem
>>>> that java.util.concurrent.atomic solves."
>>>>
>>>> As a minor point, I wanted synchronization on reads to be as
>>>> minor/invisible as possible, to affect the readers' behavior as little
>>>> as possible (in comparison to their behavior when the value they're
>>>> reading a constant value with no synchronization).
>>>>
>>>> But if AtomicReference is simply the wrong tool to use here, I
>>>> shouldn't use it.  That's fine.
>>>>
>>>>>
>>>>>>> If you want to be able to CAS a reference to a j.t.Instant, you're
>>>>>>> going to have to wrap accesses to it in a synchronized block.  This is
>>>>>>> a direct consequence of the JVM's inability to CAS multi-word objects.
>>>>>>
>>>>>> This is confusing.
>>>>>>
>>>>>> Surely this isn’t talking about CASing a reference? The contents of
>>>>>> the object can’t be assumed to have any atomicity properties,
>>>>>> whether it is j.t.Instant or not.
>>>>>
>>>>> I agree.  I'm trying to look at what the OP actually wants to do: I
>>>>> assume this is some kind of atomic timestamp, and the OP wants to be
>>>>> able to CAS an instance of j.u.Instant.
>>>>
>>>> It was more of a general worry and question.  Should I ever use
>>>> AtomicReference with value-based classes?  It sounds like the answer
>>>> is no.
>>>>
>>>> But here's some code that illustrates the specific problem I was
>>>> trying to solve.  I think it "works" right now, but that it's in
>>>> violation of the spec for value-based classes and so possibly not
>>>> future-proof, and I think I understand how to fix it now.  Thanks for
>>>> the tips.
>>>>
>>>>     class MutableClock {
>>>>
>>>>         static MutableClock create(Instant instant, ZoneId zone) {
>>>>             return new MutableClock(
>>>>                     new AtomicReference<>(instant),
>>>>                     zone);
>>>>         }
>>>>
>>>>         private final AtomicReference<Instant> instantHolder;
>>>>         private final ZoneId zone;
>>>>
>>>>         private MutableClock(
>>>>                 AtomicReference<Instant> instantHolder,
>>>>                 ZoneId zone) {
>>>>             this.instantHolder = instantHolder;
>>>>             this.zone = zone;
>>>>         }
>>>>
>>>>         Instant instant() {
>>>>             return instantHolder.get();
>>>>         }
>>>>
>>>>         ZoneId getZone() {
>>>>             return zone;
>>>>         }
>>>>
>>>>         void setInstant(Instant newInstant) {
>>>>             instantHolder.set(newInstant);
>>>>         }
>>>>
>>>>         void add(Duration amountToAdd) {
>>>>             // this is the part that uses == and CAS
>>>>             instantHolder.updateAndGet(
>>>>                   instant -> instant.plus(amountToAdd));
>>>>         }
>>>>
>>>>         MutableClock withZone(ZoneId newZone) {
>>>>             // conveniently, AtomicReference also acts as a
>>>>             // vehicle for "shared updates" between instances
>>>>             // of my class
>>>>             return new MutableClock(instantHolder, newZone);
>>>>         }
>>>>     }
>>>>
>>>> -Michael
>>>> _______________________________________________
>>>> Concurrency-interest mailing list
>>>> [hidden email]
>>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>>
>>>>
>>>> _______________________________________________
>>>> Concurrency-interest mailing list
>>>> [hidden email]
>>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>>
>>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Stephen Colebourne-2
In reply to this post by Gil Tene-2
Given:

Instant i1 = Instant.ofEpochMilli(2);
Instant i2 = Instant.ofEpochMilli(2);

In Java 8:

i1.equals(i2) is true
i1 == i2  is false

And in some future version, i1 == i2  might be true.

But this is not especially radical. Java 10 could introduce a cache in
the factory method that always returns the same instance. In fact,
there already is a cache if you call
Instant.ofEpochMilli(0);

The key phrase in
http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
is "A program may produce unpredictable results if it attempts to
distinguish two references to equal values of a value-based class".
IMO, the intent is to tell everyone that they shouldn't try to tell
the difference between two instances using ==, and if they do their
program may change meaning in the future (ie. be unpredictable, but
not stupidly unpredictable as some in the thread are suggesting).

Stephen


On 6 July 2017 at 17:33, Gil Tene <[hidden email]> wrote:

>
> It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen".
>
> Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.
>
> For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).
>
> We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.
>
> It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.
>
> For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.
>
> One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...
>
> This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.
>
> Sent from my iPad
>
> On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:
>
> :-) the one causing Byzantine failures!
>
> Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.
>
> All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).
>
>
> Alex
>
>
> On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:
>
> just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
> n  Sebastian
>
> From: Concurrency-interest [mailto:[hidden email]] On Behalf Of Alex Otenko
> Sent: Thursday, July 06, 2017 10:17 AM
> To: Gil Tene
> Cc: [hidden email]
> Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
>
>
>
> On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
>
>
>
> Sent from my iPad
>
>
> On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:
>
> All it is saying is:
>
>   LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
>   LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
>   LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
>
> a==b && b==c can be true and can be false
>
>
> It also means that even when:
>
>   LocalDateTime d = a;
>   ...
>   (a == d) may or may not be true. And may change whether it is true or not at any time,
>
>
> I meant an even stronger assertion:
>
> assert (a==b) == (b==a) : "No Byzantine optimizations"
> assert (a==d) == (a==d): “No Byzantine optimizations"
>
> Alex
>
>
>
>
>
>
> Alex
>
>
> On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
>
>
>
> Sent from my iPad
>
>
> On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:
>
> Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content.
> There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
>
> .equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
>
> For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
>   int a = 5;
>   int b = 5;
>   boolean y = (a == b);  // true
>
> For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
>   Integer a = new Integer(5);
>   Integer b = new Integer(5);
>   boolean x = a.equals(b);   // true
>   boolean y = (a == b);   // false
>
> And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
>
>   LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
>   LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
>   boolean x = a.equals(b);   // true
>   boolean y = (a == b);   // unpredictable, undefined, who knows.
>                                          // Could be true, could be false.
>                                          // Could theoretically change the values of a or b, or of something else
>
>
>
>
> On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:
>
>
> I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.
>
> While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
> For example:
> - It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
> - It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
> - It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
> - It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).
>
> So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.
>
> — Gil.
>
> > On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
> >
> > I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
> >
> > By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
> >
> > If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
> >
> >
> > On 2017-07-05 09:20 PM, Gil Tene wrote:
> >> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
> >> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
> >> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
> >> — Gil.
> >>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
> >>>
> >>> AtomicReference and VarHandle are specified to use == in compareAndSet
> >>> (and related) operations [1].  Using == to compare instances of
> >>> value-based classes may lead to "unpredictable results" [2].  Does
> >>> this mean I should avoid using compareAndSet with arguments that are
> >>> instances of value-based classes?
> >>>
> >>> It seems like the documentation clearly tells me "yes, avoid doing
> >>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
> >>> VarHandle are exempt somehow.  Otherwise, how do I implement
> >>> non-broken compareAndSet and updateAndGet for a java.time.Instant
> >>> value for example?  Do I have to box the value in something that's not
> >>> a value-based class first, like AtomicReference<Box<Instant>>?
> >>>
> >>> -Michael
> >>>
> >>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
> >>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
> >
> > _______________________________________________
> > Concurrency-interest mailing list
> > [hidden email]
> > http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
>
>
>
> Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Brian S O'Neill-3
It sounds like the documentation should be updated to prevent further
confusion. Perhaps this example (or something like it) should be provided.

On 2017-07-06 02:29 PM, Stephen Colebourne wrote:

> Given:
>
> Instant i1 = Instant.ofEpochMilli(2);
> Instant i2 = Instant.ofEpochMilli(2);
>
> In Java 8:
>
> i1.equals(i2) is true
> i1 == i2  is false
>
> And in some future version, i1 == i2  might be true.
>
> But this is not especially radical. Java 10 could introduce a cache in
> the factory method that always returns the same instance. In fact,
> there already is a cache if you call
> Instant.ofEpochMilli(0);
>
> The key phrase in
> http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
> is "A program may produce unpredictable results if it attempts to
> distinguish two references to equal values of a value-based class".
> IMO, the intent is to tell everyone that they shouldn't try to tell
> the difference between two instances using ==, and if they do their
> program may change meaning in the future (ie. be unpredictable, but
> not stupidly unpredictable as some in the thread are suggesting).
>
> Stephen
>
>
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Alex Otenko

On Jul 6, 2017, at 1:56 PM, Alex Otenko <[hidden email]> wrote:

What’s wrong with “==“ doing a sensible default thing? Like, bitwise compare the “contents”? It’s certainly no slower than calling equals() that perhaps will do more than just bitwise-compare.

Nothing "wrong" with that if we had a good specification on WHEN it means that. And "when both sides of the == are instances of value-based classes" probably doesn't cut it.

To see why, the javac compiler won't let us write:
int i = 0;
Object o = new Object();
boolean b = (o == i);
That's because int is NOT AN OBJECT.

But javac absolutely does let us write:
Object o1 = getSomeObject();
Optional o2 = getSomeOtherObject();
boolean b = (o1 == o2);
What does that == mean? What can it mean without being "surprising"?

And while it's tempting to say that here:
Optional o1 = Optional.of(objA);
Optional o2 = Optional.of(objB);
boolean b = (o1 == o2);
The == means "compare the contents". What should it mean here:
Object o1 = Optional.of(objA);
Object o2 = Optional.of(objB);
boolean b = (o1 == o2);
I suspect that the curse of being the basterd children of Object will follow instances of value based classes around for generations to come… It will be curious to see how value types deal with this same problem in an eventual working syntax. 


What’s wrong with identityHashCode producing a code based on identityHashCodes of the “contents”, or the bit contents of the primitive members?

Similarly, identityHashCode already has a meaning for Object, where it will NOT be computed based on contents. Changing that for the basterd children of Object will create all sorts of in-fighting in the family:
Optional o1 = Optional.of(objA);
int ihc1 = System.identityHashCode(o1);
...
Object o2 = o1;
int ihc2 = System.identityHashCode(o2);
boolean b = (ihc1 == ihc2); // Is this allowed to be False?

Alex

On 6 Jul 2017, at 20:23, Gil Tene <[hidden email]> wrote:

I think that performant runtime checks can be added. When you haven't stuffed indentity-lacking things into other things that explore identity, things will be just as fast. When you do, they will blow up, and speed won't matter.

The larger problem of "surprising behavior" when passing a non-identity-capable thing (basterd child of Object) to some thing that expects Object and does object things with it at some future point in time (like maybe using identity for something) is likely to come at us hard when "codes like a class, works like an int" value types are introduced. IMO, it is "hard" (as in impractical) to compile-time check this stuff away completely. You can cover some (many?) cases, but runtime issues will always remain. The situation where people are appalled at what can happen with instances of value-based classes that they may pass to innocent Object-expecting things is just a glimpse of the future. IMO an exception is the least bad thing you can do to them. Much better than letting their code run.

— Gil.

On Jul 6, 2017, at 11:52 AM, Brian S O'Neill <[hidden email]> wrote:

Although it would be nice to have value-based classes truly supported, because the java.time classes are defined as ordinary classes, they can never change into becoming true value-based classes without breaking compatibility. You can't just change the definition of instance equality without completely breaking the language completely. Improper use of a weak value-based class should at the very least trigger a compiler warning, but a full runtime check is too extreme.

Consider how these checks are implemented by the compiler. Adding a runtime check would be equivalent to making every == check, cas, etc behave like a virtual method call. I wouldn't be terribly happy to see a performance regression introduced in something so fundamental and used everywhere.

Also consider problems resulting an exception thrown from the == operator. This isn't supposed to happen. Any piece of code which is designed to be fault tolerant (via exception handling) is now broken, because it assumed (correctly) that fundamental language design elements don't change.


On 2017-07-06 11:15 AM, Gil Tene wrote:
David, the below is a (potentially good) argument for not allowing the creation of subclasses of Object that do not have well defined support identity, identity comparison, identity hashing, or synchronization, since Object supports all those, things that hold Object instances may very well make use of them.
But that horse has long fled the barn. We can argue that value-based classes should not have been specified in Java 8. Or that the future value types should not be derived from Object. But the first case is already in the Java spec, and the second is likely coming (and is sneakily able to use the first as a precedent).
For the "how should we specify things?" discussion, I'm actually squarely on the side of "things with no identity should never have been derived from Object" of this argument. E.g. I would advise other language specifications to avoid making the same mistake, either by not giving the base Object class identity to begin with, or by creating a separate orthogonal type hierarchy for value types and "value based" classes. However, I don't see a way to "fix" the mistake already made, and we have to deal with the language and the machine as spec'ed, not as we wish it were. And so does anyone writing code in the language.
In the context of that reality, we are discussing what correct uses of those new "basterd children of Object" are. And since the basterds clearly have no identity, using any logic that relies on identity behavior in any way is wrong.
Sent from my iPad
On Jul 6, 2017, at 10:53 AM, Gil Tene <[hidden email] <[hidden email]>> wrote:
Hence my suggestion that identity-based operations on instances of value-based classes should throw exceptions... Right now they silently do unpredictable things, and should be avoided in any case (but harder to know/find when you accidentally use them).

Sent from my iPad

On Jul 6, 2017, at 10:46 AM, Alex Otenko <[hidden email] <[hidden email]>> wrote:

Are they subclasses of Object or not? If they are not, no questions. If they are, someone still needs to explain how exactly the “identity based operations” can be avoided safely.

List<j.u.Optional> is just a List underneath, and searching for an item may use “identity based operations”, whether you want it or not - depending on what implementation of List you happen to use.

Alex

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Should I avoid compareAndSet with value-based classes?

Gil Tene-2
In reply to this post by Stephen Colebourne-2

> On Jul 6, 2017, at 2:29 PM, Stephen Colebourne <[hidden email]> wrote:
>
> Given:
>
> Instant i1 = Instant.ofEpochMilli(2);
> Instant i2 = Instant.ofEpochMilli(2);
>
> In Java 8:
>
> i1.equals(i2) is true
> i1 == i2  is false
>
> And in some future version, i1 == i2  might be true.
>
> But this is not especially radical. Java 10 could introduce a cache in
> the factory method that always returns the same instance. In fact,
> there already is a cache if you call
> Instant.ofEpochMilli(0);
>
> The key phrase in
> http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
> is "A program may produce unpredictable results if it attempts to
> distinguish two references to equal values of a value-based class".

Read on, past the first comma. The full paragraph says:

"A program may produce unpredictable results if it attempts to distinguish two references to equal values of a value-based class, whether directly via reference equality or indirectly via an appeal to synchronization, identity hashing, serialization, or any other identity-sensitive mechanism. Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided."

> IMO, the intent is to tell everyone that they shouldn't try to tell
> the difference between two instances using ==,

That's one tiny part of what they tell you not to do. read the full sentence it. The "or any other identity-sensitive mechanism" leaves no room for interpretations that start with "but if == is true, then…".

Also note that the "an appeal to synchronization" part absolutely applies to atomic things like CAS that may attempt to operate based on an identity-sensitive mechanism...

> and if they do their
> program may change meaning in the future (ie. be unpredictable, but
> not stupidly unpredictable as some in the thread are suggesting).

Stupidity is in the eye of the beholder, I guess.

Unpredictable effects and unpredictable results are just that. Unpredictable. Not just in the future. Not just when the unpredictability makes sense. Also run-to-run, millisecond-to-millisecond, value-to-value. When-I-feel-like-it-to-when-I-dont.

E.g. nowhere does it say that if == is true then .equals() has to be true. That's just wishful thinking by folks that want to say "that would be stupid" because it would be "surprising" to them.

The optimizers will only be fed with the rules of what they must follow. And for e.g. == on instances of value-based classes, that is plainly "this specific == doesn't have a meaning. Do whatever you want to do or need to do with that.". It's not that there is some well-defined meaning that something is "smartly" attempting to ignore. It's that there is literally no defined meaning. Optimizers won't intentionally look to do "stupid" things. They will simply follow the actual rules, and not make up new ones. If the rules allow "stupid", and "stupid" seems to be profitable, an optimizer may very well do it. The surprising, unpredictable results and behavior that may come out of it is nobody's fault but the the person who put in the == to begin with, when explicitly told 17 different ways "don't do that", accompanied with scary statements like: "this may have unpredictable effects", and "your *program* (read: not just the == operation you'd like to try and reason about) may produce unpredictable results".

>
> Stephen
>
>
> On 6 July 2017 at 17:33, Gil Tene <[hidden email]> wrote:
>>
>> It says: "Use of such identity-sensitive operations on instances of value-based classes may have unpredictable effects and should be avoided." It does not say what the reason for the unpredictable effect may be and WHEN you shouldn't use identity based operations, it warns you not to use them for any reason whatsoever. Can't be much more clear than that, and you don't need to be a JVM or compiler implementor to understand it. It means "don't do that". And "if you do that, very surprising things may (or may not) happen".
>>
>> Acting on a current understanding and perception of what implementations actually do, and saying "I thought that what it really means is that using identity in some way X would be unreliable because of effect Y, but using identity in case Z is ok, because I don't see why it shouldn't be" is a wrong reading of this clear admonition to not use identity for anything. Doing so will come back to bite you, either now or in the future.
>>
>> For example, instances of value-based classes have the [well documented] quality of being "freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to equals() in any computation or method invocation should produce no visible change in behavior." The JVM may (and likely will at some point will) use this quality freely in some optimizations, A simple and obviously valid resulting optimization would be for == to always be evaluated as false when the operands are instances of value-based classes: since the JVM *may* freely substitute the instances of either side of the == evaluation with some instance that is equal according to equals(), it can choose to do so in all evaluations of ==, which would mean that the two sides are never the same instance, and would then mean that the JVM can treat all code that would only execute if == were true as dead code. Similarly, != may trivially be evaluated as always-true. And since these optimizations may or may not be applied in different places and times, they may lead to seemingly random evaluation of == or != for identical code on identical data (for the exact same, unmodified values of a and d, a will sometimes be equal to d and sometimes not, and at the same point in code, depending on mood).
>>
>> We could further discuss whether or not the JVM is allowed to "falsely" indicate that == is true (or that != is false) even when the instances differ in value (so are not .equals()). It is. Doing that may certainly surprise anyone who uses the identity based == for anything to do with instances of value-based classes, even tho using it would be silly given that == might obviously be always-false. For example, I could see how someone may mistakenly try to use == as an "optimization" on the assumption that if they get lucky and == is true, .equals() must be true as well, and that evaluating == might be cheaper, but they would still "do the right thing" in the != case. But that would be a mistake, and a clear violation of the "don't do that" admonition above. The cases where the result of == can be *unpredictable* are not limited to cases where the JVM freely substitutes instances for other equal() ones, that's just one example of how the JVM may obviously and validly use one known quality of value-based classes. But another key quality of instances of value based classes is that they "are considered equal solely based on equals(), not based on reference equality (==)". There is nothing there that limits us to "if == is true, equals() must be true as well". It may be convenient to think otherwise when wanting to explain how breaking the rules in some specific way is still ok (and currently seems to work). But it's not. Bottom line: The JVM *may* choose to make == always-true. Nothing wrong with that.
>>
>> It is dangerous (and nearly impossible) to deduce which optimizations may or may not happen when they are clearly allowed by the specified set of rules and qualities. The defined qualities are what matter, and optimizations that indirectly result from the propagation of those qualities are allowed and may (or may  not) happen. Instance identity either exists or doesn't, and instance Identity checks either have meaning, or they don't. If they do, certain things follow (like .equals() always being true if the identity of the twin instances is the same, as tested by ==). If they don't, then identity checks are meaningless, and can be discarded or conveniently evaluated in ways that seem profitable.
>>
>> For "instances" of value-based classes, instance identity does not exist. Unfortunately, unlike value types, where the operand == is defined to act on value and not on identity, the operand == is undefined for instances of value-based classes. It certainly does not mean "if true, the identity of these things is the same", and it certainly doesn't mean "if false, these things are not equal". But it also doesn't mean "if true, these things are equal". It is *undefined*, specified with "may have unpredictable effects", and users are clearly told not to use it for anything.
>>
>> One can argue that the spec should change, e.g. add a statement that would have the effect of requiring "if == is true then .equals() is also true", and would prevent or limit certain unpredictable effects when considering the identity of identity-less things, but I suspect that writing that down in actual words would be painful given the necessary "there is no meaning to identify, but..." logic. We could also look to redefine the meaning of certain operands, e.g. == and != can be dealt with as they are in value types, but compare in compareAndSet is more challenging...
>>
>> This is [partly] why I think that throwing an exception (or even a compile-time error where possible) when encountering == or != operations (and any of the other undefined behavior ones) on instances of value-based classes is a good idea, and something that should start happening ASAP. Any such operation is wrong (literally) by definition, and the "may have unpredictable effects" statement in the spec is certainly wide enough to allow exception throwing. It is wide enough to allow much worse things to happen, and silent unpredictable and undefined behavior, while allowed, is worse than preventing the code from executing. The same way we wouldn't argue that synchronized(int) should simply be "undefined" but silently allowed to run with unpredictable effects, we shouldn't argue that synchronized(LocalDateTime) should.
>>
>> Sent from my iPad
>>
>> On Jul 6, 2017, at 3:04 AM, Alex Otenko <[hidden email]> wrote:
>>
>> :-) the one causing Byzantine failures!
>>
>> Given how underspecified the things generally are, and that the target audience of such javadoc is not a JVM implementor, we shouldn’t read too much into the possible freedoms the vague wording seems to imply. It shouldn’t suddenly break the promises about identity equality for specific instances.
>>
>> All it’s saying is that, like Integer.from(10) may or may not return the same instance. It may or may not work the same way throughout the JVM’s lifetime, allowing the implementors to choose suitable caching strategies, code optimizations, etc - therefore should not rely on comparing identities, and such; for example, synchronized(Integer.from(10)) does not guarantee neither lock freedom, nor deadlock freedom. It should not say that suddenly it is unsafe to compare identities (like Gil suggests JVM could start throwing exceptions). It should not say that suddenly we shouldn’t be able to CAS (like Gil says suddenly the reference to instance can sneakily be replaced with something else).
>>
>>
>> Alex
>>
>>
>> On 6 Jul 2017, at 10:12, Millies, Sebastian <[hidden email]> wrote:
>>
>> just out of curiosity: I am familiar with the term “Byzantine failure”, but what is a “Byzantine optimization”?
>> n  Sebastian
>>
>> From: Concurrency-interest [mailto:[hidden email]] On Behalf Of Alex Otenko
>> Sent: Thursday, July 06, 2017 10:17 AM
>> To: Gil Tene
>> Cc: [hidden email]
>> Subject: Re: [concurrency-interest] Should I avoid compareAndSet with value-based classes?
>>
>>
>>
>> On 6 Jul 2017, at 08:47, Gil Tene <[hidden email]> wrote:
>>
>>
>>
>> Sent from my iPad
>>
>>
>> On Jul 6, 2017, at 12:38 AM, Alex Otenko <[hidden email]> wrote:
>>
>> All it is saying is:
>>
>>  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
>>  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
>>  LocalDateTime c = LocalDateTime.parse("2007-12-03T10:15:30");
>>
>> a==b && b==c can be true and can be false
>>
>>
>> It also means that even when:
>>
>>  LocalDateTime d = a;
>>  ...
>>  (a == d) may or may not be true. And may change whether it is true or not at any time,
>>
>>
>> I meant an even stronger assertion:
>>
>> assert (a==b) == (b==a) : "No Byzantine optimizations"
>> assert (a==d) == (a==d): “No Byzantine optimizations"
>>
>> Alex
>>
>>
>>
>>
>>
>>
>> Alex
>>
>>
>> On 6 Jul 2017, at 08:28, Gil Tene <[hidden email]> wrote:
>>
>>
>>
>> Sent from my iPad
>>
>>
>> On Jul 5, 2017, at 11:51 PM, Henrik Johansson <[hidden email]> wrote:
>>
>> Oh, without having followed the value type discussions I think it was a mistake to not "fix" equality. Why not make it a deep comparison if the reference is different? If it points to the same object we are done otherwise start checking the struct content.
>> There may be a lot I missed here but a new type of object could be allowed to have different meaning equality. Right?
>>
>> .equals() means what you want it to mean. == and != (and the compare in compareAndSet) mean very specific things, and cannot be overridden.
>>
>> For non-reference value types (int, long, char, etc.), == and != are value comparisons. An int has no identity. Just a value:
>>  int a = 5;
>>  int b = 5;
>>  boolean y = (a == b);  // true
>>
>> For references to instances of (non value-based) classes, == and != can be thought of as comparing the value of the reference (and not the contents of the object instances). This is an identity comparison, which ignores values within the object:
>>  Integer a = new Integer(5);
>>  Integer b = new Integer(5);
>>  boolean x = a.equals(b);   // true
>>  boolean y = (a == b);   // false
>>
>> And for references to value-based classes (which is a relatively new thing, but is part of Java 8), the meaning of == and != appears to be undefined. E.g.:
>>
>>  LocalDateTime a = LocalDateTime.parse("2007-12-03T10:15:30");
>>  LocalDateTime b = LocalDateTime.parse("2007-12-03T10:15:30");
>>  boolean x = a.equals(b);   // true
>>  boolean y = (a == b);   // unpredictable, undefined, who knows.
>>                                         // Could be true, could be false.
>>                                         // Could theoretically change the values of a or b, or of something else
>>
>>
>>
>>
>> On Thu, 6 Jul 2017, 07:12 Gil Tene, <[hidden email]> wrote:
>>
>>
>> I'd take that documentation seriously. It basically says that ==, !=, synchronization, identity hashing, and serialization are undefined behaviors.
>>
>> While the *current* implementations may carry some semi-intuitive behvaiors, e.g. where == indicates true when comparing two references to instances of a value-based class where the value of the references is the same, there is no guarantee that at some point in the [near or far] future that behavior will remain. Specifically, attempting == (or !=, or synchronization, etc., including compareAndSet) on a reference to a value based class is allowed to do ANYTHING in the future.
>> For example:
>> - It may throw an exception (something it should probably start doing ASAP to avoid future surprises).
>> - It may return always-false, even when the two references are "to the same instance" (and probably will, through many possible value-based compiler optimizations that will erase the unneeded notion of reference and identity).
>> - It may overwrite random locations in memory or to variables that the code performing the operation has the privilege to write to (which it probably shouldn't, but that's certainly included in what "undefined" and "unpredictable effects" can mean).
>> - It may sometimes do one of the above, and sometimes seem to be doing what you mean it to do. Switching between modes on a whim (e.g. when a tier 2 optimizing compilation is applied, or when the mutton is nice and lean and the tomato is ripe).
>>
>> So no, there is no way for compareAndSet to work "correctly" on a reference to an instance of a value-based class. Even if it happens to appear to work "correctly" now, expect it to blow up in bad and potentially silent ways in the future.
>>
>> — Gil.
>>
>>> On Jul 5, 2017, at 9:47 PM, Brian S O'Neill <[hidden email]> wrote:
>>>
>>> I think the wording in the value-based document is too strong. It's perfectly fine to compare value based instances using ==, but it can lead to confusing results when comparing distinct instances with equivalent state. Using compareAndSet with a box isn't necessary for it to work "correctly" with a value-based class.
>>>
>>> By "correctly", I mean the compareAndSet operation works correctly, using == comparison. However, if your intention is for compareAndSet to compare Instants based on their state, then this of course won't work properly.
>>>
>>> If you want to perform a compareAndSet for an Instant's state (time since epoch), then you need to use something that can be compared atomically. This means the state must be representable in a 64-bit value or smaller. The Instant class measures time using a 64-bit long and a 32-bit int, and so this state cannot be compared atomically. You'd have to chop off some precision or use something else.
>>>
>>>
>>> On 2017-07-05 09:20 PM, Gil Tene wrote:
>>>> Reference equality for value based classes (as referenced below) lacks meaning, as there is no notion of identity in such classes (only a notion of value). And since compareAndSet on reference fields is basically an idenitity-based operation [in the compare part], the two won't mix well logically.
>>>> Specifically, while two references to e.g. java.time.LocalDateTime instances being == to each other *probably* means that the two are actually equal in value, the opposite is not true: Being != to each other does NOT mean that they are logically different. As such, the "compare" part in compareAndSet may falsely fail even when the two instances are logically equal to each other, leaving the rest of your logic potentially exposed.
>>>> Bottom line: given the explicit warning to not use == and != on references to value-based instances, I'd avoid using compareAndSet on those references. If you really need to use a value-based class in your logic, consider boxing it in another object that has [normal] identity.
>>>> — Gil.
>>>>> On Jul 5, 2017, at 8:59 PM, Michael Hixson <[hidden email]> wrote:
>>>>>
>>>>> AtomicReference and VarHandle are specified to use == in compareAndSet
>>>>> (and related) operations [1].  Using == to compare instances of
>>>>> value-based classes may lead to "unpredictable results" [2].  Does
>>>>> this mean I should avoid using compareAndSet with arguments that are
>>>>> instances of value-based classes?
>>>>>
>>>>> It seems like the documentation clearly tells me "yes, avoid doing
>>>>> that" but I'm hoping I misunderstood, or maybe AtomicReference and
>>>>> VarHandle are exempt somehow.  Otherwise, how do I implement
>>>>> non-broken compareAndSet and updateAndGet for a java.time.Instant
>>>>> value for example?  Do I have to box the value in something that's not
>>>>> a value-based class first, like AtomicReference<Box<Instant>>?
>>>>>
>>>>> -Michael
>>>>>
>>>>> [1] http://download.java.net/java/jdk9/docs/api/java/util/concurrent/atomic/AtomicReference.html#compareAndSet-V-V-
>>>>> [2] http://download.java.net/java/jdk9/docs/api/java/lang/doc-files/ValueBased.html
>>>
>>> _______________________________________________
>>> Concurrency-interest mailing list
>>> [hidden email]
>>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>>
>>
>>
>> Software AG – Sitz/Registered office: Uhlandstraße 12, 64297 Darmstadt, Germany – Registergericht/Commercial register: Darmstadt HRB 1562 - Vorstand/Management Board: Karl-Heinz Streibich (Vorsitzender/Chairman), Eric Duffaut, Dr. Wolfram Jost, Arnd Zinnhardt, Dr. Stefan Sigg; - Aufsichtsratsvorsitzender/Chairman of the Supervisory Board: Dr. Andreas Bereczky - http://www.softwareag.com
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
>>
>> _______________________________________________
>> Concurrency-interest mailing list
>> [hidden email]
>> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
>>
> _______________________________________________
> Concurrency-interest mailing list
> [hidden email]
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
123456