Synchronized blocks in value constructors

João Mendonça jf.mend at gmail.com
Mon Sep 25 10:52:07 UTC 2023


Yes, I am aware that declaring a value class with a marker interface such
as "LooselyConsistentValue" does the same thing.

...for being non-atomic is bug-prone.
>

I agree that this is crucial. The two safety advantages I mentioned are
precisely about this.
To reiterate: in my proposal, users must opt-out of atomicity by writing a
synchronized block that does not include all field declarations.
I'm proposing this syntax for these reasons:
 - this particular syntax, as far as I know, has not been analyzed yet
 - for the advantages I wrote comparing with the current proposal
 - I feel like we are in the syntax-bikeshedding-phase of this particular
issue

On Mon, Sep 25, 2023 at 10:39 AM - <liangchenblue at gmail.com> wrote:

> Honestly, I don't understand why you propose this, for synchronized is
> ALREADY the default behavior of Value Classes per JEP 401. By default, all
> fields in a value class are synchronized (non-atomic), so you won't see a
> Range where min > max. The current proposed syntax asks users to opt-in
> into non-atomic (or non-synchronized in your words) for being non-atomic
> is bug-prone.
>
> Chen Liang
>
> On Mon, Sep 25, 2023 at 5:01 PM João Mendonça <jf.mend at gmail.com> wrote:
>
>> Hello Chen,
>>
>>
>> Thank you very much for your response.
>> To address the fragility issue you raised, I would modify the new syntax
>> proposal to:
>>
>> *** synchronized blocks in value class field declarations. ***
>>
>> To your very good point on granularity, I think that synchronized blocks
>> could still be considered more readable than having to segregate fields in
>> separate value classes and using some other class modifier/keyword to
>> indicate non-atomicity.
>> All the other advantages/disadvantages would remain the same.
>> Your example would become:
>>
>> value class Container {
>>     synchronized {int a, b;}
>>     int c;
>>     Container(int a, int b, int c) {
>>          this.a = a;
>>          this.b = b;
>>          this.c = c;
>>     }
>> }
>>
>>
>> João Mendonça
>>
>>
>> On Mon, Sep 25, 2023 at 2:08 AM - <liangchenblue at gmail.com> wrote:
>>
>>> Hello Joao,
>>> I believe the synchronized block proposal is fragile and isn't a good
>>> hint to the VM. Each constructor can declare its own synchronization
>>> groups, which makes behaviorally-correct optimization harder.
>>> For your purpose where you only need to declare some of the properties
>>> of the value class atomically together, you can group those properties in
>>> an atomic (regular) value class. Then, you can include these regular value
>>> classes in a non-atomic value class.
>>>
>>> Say you have this:
>>> value class Container {
>>>     int a, b, c;
>>>     Container(int a, int b, int c) {
>>>          synchronized { this.a = a; this.b = b; }
>>>          this.c = c;
>>>     }
>>> }
>>>
>>> Why not this instead:
>>> nonatomic value class Container {
>>>     value class Constraint {
>>>         int a, b;
>>>         Constraint(int a, int b) { this.a = a; this.b = b; }
>>>     }
>>>     Constraint ab; int c;
>>>     Container(int a, int b, int c) {
>>>          this.ab = new Constraint(a, b);
>>>          this.c = c;
>>>     }
>>> }
>>>
>>> Chen Liang
>>>
>>> On Mon, Sep 25, 2023 at 8:58 AM João Mendonça <jf.mend at gmail.com> wrote:
>>>
>>>> I would like to propose a new syntax to specify that, in a value class,
>>>> some fields must be assigned atomically together:
>>>>
>>>> *** synchronized blocks in value class constructors. ***
>>>>
>>>>
>>>> Advantages:
>>>>
>>>>     - granularity - only the specific fields involved in an invariant
>>>> need to be assigned in the same synchronized block. Multiple blocks can be
>>>> used for independent invariants. Tearing is allowed between blocks and
>>>> between fields assigned outside blocks. VMs could take advantage of this to
>>>> perform optimizations.
>>>>     - economy - no new keyword/annotation/interface needed.
>>>>     - compatibility - synchronized blocks are currently illegal in
>>>> constructors.
>>>>     - safety - just like with identity classes, the absence of a
>>>> synchronized block in a constructor means that the whole constructor is
>>>> synchronized, i.e. all fields are written atomically.
>>>>     - safety - an empty synchronized block is required to indicate
>>>> that tearing is allowed between any fields.
>>>>     - clarity - "A synchronized block of field assignments" is a very
>>>> intuitive description of the semantics involved, given the meaning of the
>>>> word "synchronized" in english.
>>>>
>>>>
>>>> Disadvantages:
>>>>
>>>>     - aesthetics - an empty synchronized block is required to indicate
>>>> that tearing is allowed between any fields.
>>>>     - safety - a user of a value class has no automatic way to be
>>>> informed of if/where tearing may occur (can be fixed with an update to
>>>> the generation of java docs).
>>>>     - clarity - synchronized blocks (§14.18.) have two meanings:
>>>>         - The old meaning in regular methods: only one thread may be
>>>> running inside of a block for the object given in the expression clause
>>>>         - The new meaning in constructors: all assignments in a block
>>>> are written atomically (no expression clause)
>>>>
>>>> Example:
>>>>
>>>>     value class Range {
>>>>         long start, end;
>>>>         public Range(long start, long end) {
>>>>             if (start > end) throw new IllegalArgumentException();
>>>>             synchronized {
>>>>                 this.start = start;
>>>>                 this.end = end;
>>>>             }
>>>>         }    }
>>>>
>>>> Having all fields assigned in the same synchronized block, as above, is equivalent to declaring no synchronized blocks:
>>>>
>>>>     value class Range {
>>>>         long start, end;
>>>>
>>>>         public Range(long start, long end) {
>>>>             if (start > end) throw new IllegalArgumentException();
>>>>             this.start = start;
>>>>             this.end = end;
>>>>         }    }
>>>>
>>>>
>>>> Another example:
>>>>
>>>>     value class Point {
>>>>         double x, y;
>>>>                 public Point(double x, double y) {
>>>>             synchronized {}
>>>>             this.x = x;            this.y = y;
>>>>         }    }
>>>>
>>>>
>>>>
>>>> João Mendonça
>>>>
>>>>
>>
>> On Mon, Sep 25, 2023 at 2:08 AM - <liangchenblue at gmail.com> wrote:
>>
>>> Hello Joao,
>>> I believe the synchronized block proposal is fragile and isn't a good
>>> hint to the VM. Each constructor can declare its own synchronization
>>> groups, which makes behaviorally-correct optimization harder.
>>> For your purpose where you only need to declare some of the properties
>>> of the value class atomically together, you can group those properties in
>>> an atomic (regular) value class. Then, you can include these regular value
>>> classes in a non-atomic value class.
>>>
>>> Say you have this:
>>> value class Container {
>>>     int a, b, c;
>>>     Container(int a, int b, int c) {
>>>          synchronized { this.a = a; this.b = b; }
>>>          this.c = c;
>>>     }
>>> }
>>>
>>> Why not this instead:
>>> nonatomic value class Container {
>>>     value class Constraint {
>>>         int a, b;
>>>         Constraint(int a, int b) { this.a = a; this.b = b; }
>>>     }
>>>     Constraint ab; int c;
>>>     Container(int a, int b, int c) {
>>>          this.ab = new Constraint(a, b);
>>>          this.c = c;
>>>     }
>>> }
>>>
>>> Chen Liang
>>>
>>> On Mon, Sep 25, 2023 at 8:58 AM João Mendonça <jf.mend at gmail.com> wrote:
>>>
>>>> I would like to propose a new syntax to specify that, in a value class,
>>>> some fields must be assigned atomically together:
>>>>
>>>> *** synchronized blocks in value class constructors. ***
>>>>
>>>>
>>>> Advantages:
>>>>
>>>>     - granularity - only the specific fields involved in an invariant
>>>> need to be assigned in the same synchronized block. Multiple blocks can be
>>>> used for independent invariants. Tearing is allowed between blocks and
>>>> between fields assigned outside blocks. VMs could take advantage of this to
>>>> perform optimizations.
>>>>     - economy - no new keyword/annotation/interface needed.
>>>>     - compatibility - synchronized blocks are currently illegal in
>>>> constructors.
>>>>     - safety - just like with identity classes, the absence of a
>>>> synchronized block in a constructor means that the whole constructor is
>>>> synchronized, i.e. all fields are written atomically.
>>>>     - safety - an empty synchronized block is required to indicate
>>>> that tearing is allowed between any fields.
>>>>     - clarity - "A synchronized block of field assignments" is a very
>>>> intuitive description of the semantics involved, given the meaning of the
>>>> word "synchronized" in english.
>>>>
>>>>
>>>> Disadvantages:
>>>>
>>>>     - aesthetics - an empty synchronized block is required to indicate
>>>> that tearing is allowed between any fields.
>>>>     - safety - a user of a value class has no automatic way to be
>>>> informed of if/where tearing may occur (can be fixed with an update to
>>>> the generation of java docs).
>>>>     - clarity - synchronized blocks (§14.18.) have two meanings:
>>>>         - The old meaning in regular methods: only one thread may be
>>>> running inside of a block for the object given in the expression clause
>>>>         - The new meaning in constructors: all assignments in a block
>>>> are written atomically (no expression clause)
>>>>
>>>> Example:
>>>>
>>>>     value class Range {
>>>>         long start, end;
>>>>         public Range(long start, long end) {
>>>>             if (start > end) throw new IllegalArgumentException();
>>>>             synchronized {
>>>>                 this.start = start;
>>>>                 this.end = end;
>>>>             }
>>>>         }    }
>>>>
>>>> Having all fields assigned in the same synchronized block, as above, is equivalent to declaring no synchronized blocks:
>>>>
>>>>     value class Range {
>>>>         long start, end;
>>>>
>>>>         public Range(long start, long end) {
>>>>             if (start > end) throw new IllegalArgumentException();
>>>>             this.start = start;
>>>>             this.end = end;
>>>>         }    }
>>>>
>>>>
>>>> Another example:
>>>>
>>>>     value class Point {
>>>>         double x, y;
>>>>                 public Point(double x, double y) {
>>>>             synchronized {}
>>>>             this.x = x;            this.y = y;
>>>>         }    }
>>>>
>>>>
>>>>
>>>> João Mendonça
>>>>
>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/valhalla-spec-observers/attachments/20230925/3a862786/attachment-0001.htm>


More information about the valhalla-spec-observers mailing list