August 17, 2020
On 8/17/20 4:53 PM, mw wrote:
> On Monday, 17 August 2020 at 18:10:16 UTC, H. S. Teoh wrote:
>> On Mon, Aug 17, 2020 at 05:58:16PM +0000, mw via Digitalmars-d wrote:
>>> On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:
>> [...]
>>> > Chain assignment fix: > https://github.com/dlang/phobos/pull/7599
>>>
>>> Thanks for the PR, I just added comments: does this fix also work for mixed native & checked chain assignment? i.e. add to unittest:
>>>
>>> ```
>>>   long la, lb;
>>>   Checked!long ca, cb;
>>>
>>>   la = ca = lb = cb;  // mixed chain assign
>>>   ca = la = cb = lb;
>>> ```
>>
>> Currently, it doesn't work.  I'm on the fence about whether it should: the whole point of using Checked is that you don't want to automatically convert to the native type because the converted value will lose the protections conferred by Check. Assigning a Checked to a native type *might* be a mistake - you thought the variable was Checked but it wasn't, so subsequent operations on it no longer has Checked semantics even though
> 
> Yes, that's the principle we all agree. However, we are talking about opAssign() here.
> 
> The user specifies his/her intention via the variable's type declaration, e.g. native `long` vs checked `Long`. The *subsequent* operations you talking about will be on user specified variable (type), there will be no surprise here: if the LHS is declared as a `long`, the subsequent operations will be on `long`, and if the LHS is `Long`, the subsequent operations will be on `Long`, all as user has specified.
> 
> opAssign() just make the boxing/unboxing life easier between these two types. And there is not any mathematical operation performed inside opAssign(), hence for this particular function, native == checked is always true. So I think let opAssign() return the underlying type will make the drop-in replacement process more smooth, and without extra correctness concern.

Whenever I implement opAssign I have it return void and try to remember to propose that the compiler takes care of chained assignments by itself.

Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.

August 18, 2020
On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:
> On 8/17/20 4:53 PM, mw wrote:
>> On Monday, 17 August 2020 at 18:10:16 UTC, H. S. Teoh wrote:
>>> On Mon, Aug 17, 2020 at 05:58:16PM +0000, mw via Digitalmars-d wrote:
>>>> On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:
>>> [...]
>>>> > Chain assignment fix: > https://github.com/dlang/phobos/pull/7599
>>>>
>>>> Thanks for the PR, I just added comments: does this fix also work for mixed native & checked chain assignment? i.e. add to unittest:
>>>>
>>>> ```
>>>>   long la, lb;
>>>>   Checked!long ca, cb;
>>>>
>>>>   la = ca = lb = cb;  // mixed chain assign
>>>>   ca = la = cb = lb;
>>>> ```
>>>
>>> Currently, it doesn't work.  I'm on the fence about whether it should: the whole point of using Checked is that you don't want to automatically convert to the native type because the converted value will lose the protections conferred by Check. Assigning a Checked to a native type *might* be a mistake - you thought the variable was Checked but it wasn't, so subsequent operations on it no longer has Checked semantics even though
>> 
>> Yes, that's the principle we all agree. However, we are talking about opAssign() here.
>> 
>> The user specifies his/her intention via the variable's type declaration, e.g. native `long` vs checked `Long`. The *subsequent* operations you talking about will be on user specified variable (type), there will be no surprise here: if the LHS is declared as a `long`, the subsequent operations will be on `long`, and if the LHS is `Long`, the subsequent operations will be on `Long`, all as user has specified.
>> 
>> opAssign() just make the boxing/unboxing life easier between these two types. And there is not any mathematical operation performed inside opAssign(), hence for this particular function, native == checked is always true. So I think let opAssign() return the underlying type will make the drop-in replacement process more smooth, and without extra correctness concern.
>
> Whenever I implement opAssign I have it return void and try to remember to propose that the compiler takes care of chained assignments by itself.
>
> Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.


Right, the library fix (work-around) is sub-optimal, it's better be fixed by the compiler.

@Walter, it's your turn :-)


August 17, 2020
On Mon, Aug 17, 2020 at 09:23:01PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: [...]
> Whenever I implement opAssign I have it return void and try to remember to propose that the compiler takes care of chained assignments by itself.
> 
> Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.

+1.  Is there an enhancement request for this?  As Walter often says, if it's not in bugzilla, it doesn't exist. ;-)


T

-- 
If Java had true garbage collection, most programs would delete themselves upon execution. -- Robert Sewell
August 18, 2020
On 8/18/20 1:07 AM, H. S. Teoh wrote:
> On Mon, Aug 17, 2020 at 09:23:01PM -0400, Andrei Alexandrescu via Digitalmars-d wrote:
> [...]
>> Whenever I implement opAssign I have it return void and try to
>> remember to propose that the compiler takes care of chained
>> assignments by itself.
>>
>> Requiring user-defined assignment to `return *this;` was goofy in C++.
>> Requiring user-defined assignment to `return this;` is goofy in D.
>> Assignment should return void and the compiler should take care of it.
> 
> +1.  Is there an enhancement request for this?  As Walter often says, if
> it's not in bugzilla, it doesn't exist. ;-)

https://issues.dlang.org/show_bug.cgi?id=21175

Not holding my breath.

August 18, 2020
On Tue, Aug 18, 2020 at 05:39:42PM -0400, Andrei Alexandrescu via Digitalmars-d wrote: [...]
> https://issues.dlang.org/show_bug.cgi?id=21175
> 
> Not holding my breath.

If someone can kick up a PR for this, the chances would increase significantly. ;-)


T

-- 
Error: Keyboard not attached. Press F1 to continue. -- Yoon Ha Lee, CONLANG
March 24, 2021
On Saturday, 15 August 2020 at 04:28:05 UTC, mw wrote:
>   // 7. atomic won't work
>   core.atomic.atomicOp!"+="(s.sl, lb);
> //core.atomic.atomicOp!"+="(s.sL, cb);  // Error: template instance core.atomic.atomicOp!("+=", Checked!(long, Abort), Checked!(long, Abort)) error instantiating
> //core.atomic.atomicFetchAdd(s.sL, cb);  // Error: template core.atomic.atomicFetchAdd cannot deduce function from argument types !()(shared(Checked!(long, Abort)), Checked!(long, Abort)), candidates are:
> }
> ------------------------------------------------------------------------

I've been taking a crack at fixing some of these issue but I think `atomicOp` is incompatible with the premise of `Checked!T`. Either the Hook won't have the opportunity to intercept the update based on what the result would be or the update won't be atomic.

`atomicLoad`, `atomicStore`, and `cas` should be fine though as long as there is no Hook state.
March 24, 2021
On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:
> Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.

Do you mean the compiler should take care of returning *this when opAssign returns void? Because there are some use-cases for opAssign to return something different than `this`, but I cannot remember at the moment what it was. It's a niche case.
March 24, 2021
On Wednesday, 24 March 2021 at 17:23:00 UTC, Q. Schroll wrote:
> On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:
>> Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.
>
> Do you mean the compiler should take care of returning *this when opAssign returns void? Because there are some use-cases for opAssign to return something different than `this`, but I cannot remember at the moment what it was. It's a niche case.

Ideally `lhs = rhs` would always evaluate to `lhs`, as it does for the built-in assignment operator. But that would require a deprecation cycle, since, as you say, existing code could be relying on the current behavior.
March 24, 2021
On Wed, Mar 24, 2021 at 05:23:00PM +0000, Q. Schroll via Digitalmars-d wrote:
> On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:
> > Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.
> 
> Do you mean the compiler should take care of returning *this when opAssign returns void? Because there are some use-cases for opAssign to return something different than `this`, but I cannot remember at the moment what it was. It's a niche case.

I think Andrei meant that opAssign should *always* return void, and the compiler should always automatically make the RHS of `a = b;` its value. More precisely:

	struct S { ... }
	S a, b, c;
	return a = b = c;

should be lowered to:

	struct S { ... }
	S a, b, c;
	b.opAssign(c);
	a.opAssign(b);
	return a;

Having the value of `a = b` return anything other than the RHS of the assignment is goofy semantics. Since there is only one sensible meaning of `a = b = c`, the compiler should just automate it instead of requiring the user to restate the obvious (and potentially making a mistake or introducing goofy semantics that hurt the readability / maintainability of the resulting code).


T

-- 
If you're not part of the solution, you're part of the precipitate.
March 24, 2021
On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:
> On Wed, Mar 24, 2021 at 05:23:00PM +0000, Q. Schroll via Digitalmars-d wrote:
>> On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:
>> > Requiring user-defined assignment to `return *this;` was goofy in C++. Requiring user-defined assignment to `return this;` is goofy in D. Assignment should return void and the compiler should take care of it.
>> 
>> Do you mean the compiler should take care of returning *this when opAssign returns void? Because there are some use-cases for opAssign to return something different than `this`, but I cannot remember at the moment what it was. It's a niche case.
>
> I think Andrei meant that opAssign should *always* return void, and the compiler should always automatically make the RHS of `a = b;` its value. More precisely:
>
> 	struct S { ... }
> 	S a, b, c;
> 	return a = b = c;
>
> should be lowered to:
>
> 	struct S { ... }
> 	S a, b, c;
> 	b.opAssign(c);
> 	a.opAssign(b);
> 	return a;
>
> Having the value of `a = b` return anything other than the RHS

LHS I guess

> of the assignment is goofy semantics. Since there is only one sensible meaning of `a = b = c`, the compiler should just automate it instead of requiring the user to restate the obvious (and potentially making a mistake or introducing goofy semantics that hurt the readability / maintainability of the resulting code).

Does this expand to opIndexAssign and opIndexOpAssign? Because not returning by `ref` is common there and copying is not intended. What about property setters? It sure shouldn't implicitly call the getter -- and even if, a getter need not even exist. Enabling chained assignments isn't as trivial as fixing opAssign.

I now know where I've seen an assignment operator not returning a reference to the object: C++'s slice_array and gslice_array[1] have void operator= and the reason probably is that
(a) returning the (g)slice_array is conceptually wrong,
(b) returning a valarray is wrong, too.
Maybe there are constructs in D where the same reasoning applies.

[1] https://www.cplusplus.com/reference/valarray/