digitalmars.D - study: use checkedint as a drop-in replacement of native long
- mw (87/87) Aug 14 2020 (This is a follow-up from the other thread:
- H. S. Teoh (22/51) Aug 14 2020 This one should be easy to fix. Just change opAssign to return `this`
- H. S. Teoh (30/39) Aug 14 2020 More thoughts:
- Walter Bright (2/4) Aug 16 2020 This is nice work. Thank you! Please file these issues in Bugzilla.
- mw (3/9) Aug 17 2020 filed here:
- H. S. Teoh (7/18) Aug 17 2020 You might want to consider splitting up that bug into multiple smaller,
- mw (15/23) Aug 17 2020 Was hesitating between splitting or not, then thought user may
- H. S. Teoh (15/28) Aug 17 2020 Currently, it doesn't work. I'm on the fence about whether it should:
- mw (16/45) Aug 17 2020 Yes, that's the principle we all agree. However, we are talking
- Andrei Alexandrescu (6/47) Aug 17 2020 Whenever I implement opAssign I have it return void and try to remember
- mw (5/60) Aug 17 2020 Right, the library fix (work-around) is sub-optimal, it's better
- H. S. Teoh (7/14) Aug 17 2020 +1. Is there an enhancement request for this? As Walter often says, if
- Andrei Alexandrescu (3/15) Aug 18 2020 https://issues.dlang.org/show_bug.cgi?id=21175
- H. S. Teoh (7/10) Aug 18 2020 If someone can kick up a PR for this, the chances would increase
- Q. Schroll (6/10) Mar 24 2021 Do you mean the compiler should take care of returning *this when
- Paul Backus (5/15) Mar 24 2021 Ideally `lhs = rhs` would always evaluate to `lhs`, as it does
- H. S. Teoh (22/31) Mar 24 2021 I think Andrei meant that opAssign should *always* return void, and the
- Q. Schroll (15/47) Mar 24 2021 Does this expand to opIndexAssign and opIndexOpAssign? Because
- Gregor =?UTF-8?B?TcO8Y2ts?= (13/14) Mar 24 2021 If I'm reading the spec on expressions right, the compiler is
- mw (3/9) Mar 24 2021 Where is the spec you referring to?
- Q. Schroll (19/25) Mar 24 2021 You're probably mistaken. Evaluation order does not mean
- Gregor =?UTF-8?B?TcO8Y2ts?= (15/41) Mar 24 2021 Right, I've made a mistake and confused order of evaluation and
- Gregor =?UTF-8?B?TcO8Y2ts?= (3/4) Mar 24 2021 I'd actually like my claim to be proven wrong. I just can't seem
- ag0aep6g (18/25) Mar 24 2021 It's in the grammar.
- H. S. Teoh (12/22) Mar 24 2021 Link to spec please? If what you say is true, that sounds like an error
- Gregor =?UTF-8?B?TcO8Y2ts?= (4/18) Mar 24 2021 See point 1 under "Implementation Defined":
- H. S. Teoh (7/28) Mar 24 2021 The keyword here is "operands". The order of evaluation of the
- H. S. Teoh (6/7) Aug 17 2020 Chain assignment fix: https://github.com/dlang/phobos/pull/7599
- Nathan S. (8/19) Mar 24 2021 I've been taking a crack at fixing some of these issue but I
(This is a follow-up from the other thread: https://forum.dlang.org/thread/rdrqedmbknwrppbfixll forum.dlang.org) I start this new thread to discuss and improve the usage of std.experimental.checkedint as a drop-in replacement of native long. https://dlang.org/phobos/std_experimental_checkedint.html `Checked` is a struct, try to use it as a `long` require some substantial change of existing code that previously use native long. I list 8 things I've found below. Suggestions or PR welcome, e.g. even on how to improve the current implementation of `struct Checked`, or help from the compiler. Thanks. https://github.com/mingwugmail/dlang_tour/blob/master/divbug.d#L38 ------------------------------------------------------------------------ alias Long = Checked!long; void use_checked() { long la, lb, lc; // native Long ca, cb, cc; // checkedint // 0. as array literal long[] larr = [1, 2, 3]; //Long[] carr = [1, 2, 3]; // Error: cannot implicitly convert expression [1, 2, 3] of type int[] to Checked!(long, Abort)[] Long[] carr = [checked(1L), checked(2L), checked(3L)]; // more verbose // 1. checkedint cannot be chain assigned la = lb = lc = 0; //ca = cb = cc = 0; // Error: expression cc.opAssign(0) is void and has no value ca = 0; // have to do separately cb = 0; cc = 0; // 2. have to use .get to call math func writeln(std.math.sgn(la)); writeln(std.math.abs(la)); //writeln(std.math.sgn(ca)); // Error: template std.math.sgn cannot deduce function from argument types !()(Checked!(long, Abort)), candidates are: //writeln(std.math.abs(ca)); // Error: template instance std.math.abs!(Checked!(long, Abort)) error instantiating writeln(std.math.sgn(ca.get)); // need .get writeln(std.math.abs(ca.get)); // need .get // 3. no opBinaryLeft lc = la * lb; //cc = la * cb; // Error: can only * a pointer, not a int cc = cb * la; // have to switch order // 4. std.conv don't work double d = 0; lb = d.to!long; //cb = d.to!Long; // Error: template instance std.conv.to!(Checked!(long, Abort)).to!double error instantiating cb = lround(d); lb = "0".to!long; //cb = "0".to!Long; // Error: template std.conv.toImpl cannot deduce function from argument types !(Checked!(long, Abort))(string), candidates are: cb = "0".to!long; // work around ok // 5. cannot assign to shared static struct S { shared long sl; shared Long sL; } S s; s.sl = la; //s.sL = la; // Error: template std.experimental.checkedint.Checked!(long, Abort).Checked.opAssign cannot deduce function from argument types !()(long) shared, candidates are: cast()s.sL = la; // need the `cast` // 6. format %d won't work writefln("%04d", la); // output: 0000 //writefln("%04d", ca); // Expected '%s' format specifier for type 'Checked!(long, Abort)' writefln("%s", ca); // output: Checked!(long, Abort)(0), can this be just be 0? writefln("%04d", ca.get); // output: 0000 // 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: } ------------------------------------------------------------------------
Aug 14 2020
On Sat, Aug 15, 2020 at 04:28:05AM +0000, mw via Digitalmars-d wrote: [...]// 1. checkedint cannot be chain assigned la = lb = lc = 0; //ca = cb = cc = 0; // Error: expression cc.opAssign(0) is void and has no value ca = 0; // have to do separately cb = 0; cc = 0;This one should be easy to fix. Just change opAssign to return `this` instead of void, and that should solve the problem. [...]// 3. no opBinaryLeft lc = la * lb; //cc = la * cb; // Error: can only * a pointer, not a int cc = cb * la; // have to switch orderYou mean lacking opBinaryRight? That should be simple to implement?// 4. std.conv don't work double d = 0; lb = d.to!long; //cb = d.to!Long; // Error: template instance std.conv.to!(Checked!(long, Abort)).to!double error instantiating cb = lround(d);Checked should implement `opCast(T : double)()`.lb = "0".to!long; //cb = "0".to!Long; // Error: template std.conv.toImpl cannot deduce function from argument types !(Checked!(long, Abort))(string), candidates are: cb = "0".to!long; // work around okAdd a ctor to Checked that takes a string argument and parses it into a Checked value. [...]// 6. format %d won't work writefln("%04d", la); // output: 0000 //writefln("%04d", ca); // Expected '%s' format specifier for type 'Checked!(long, Abort)' writefln("%s", ca); // output: Checked!(long, Abort)(0), can this be just be 0? writefln("%04d", ca.get); // output: 0000Add an overload of toString that takes a FormatSpec argument: void toString(W,Char)(W sink, FormatSpec!Char fmt) if (isOutputRange!(W, Char)) { if (fmt.spec == "d") { ... /* do the right thing here */ } ... // etc. } These should probably be done as a series of Phobos PRs to improve the usability of Checked. T -- What's a "hot crossed bun"? An angry rabbit.
Aug 14 2020
More thoughts: On Sat, Aug 15, 2020 at 04:28:05AM +0000, mw via Digitalmars-d wrote: [...]// 2. have to use .get to call math func writeln(std.math.sgn(la)); writeln(std.math.abs(la)); //writeln(std.math.sgn(ca)); // Error: template std.math.sgn cannot deduce function from argument types !()(Checked!(long, Abort)), candidates are: //writeln(std.math.abs(ca)); // Error: template instance std.math.abs!(Checked!(long, Abort)) error instantiating writeln(std.math.sgn(ca.get)); // need .get writeln(std.math.abs(ca.get)); // need .getTechnically you *could* use `alias this` to decay it to long automatically, then these calls will work. But (1) that runs the risk of implicit conversion accidentally losing the guarantees of Checked when it silently turns into an unwrapped long, thereby defeating the purpose of using Checked; and (2) `alias this` is frowned upon these days because of its complicated relationship with subtyping. One workaround is to write forwarding overloads for these functions as member functions of Checked. But this is D, and we dislike boilerplate, so opDispatch comes to the rescue: struct Checked { ... auto opDispatch(string memb)(Checked arg) if (memb == "sgn" || memb == "abs" || ... /* etc */) { return mixin(memb ~ "(this.get)"); } ... } The bad thing is that you have to manually list the functions. But if then, you could import std.math and use introspection to extract the list of functions automatically. Good opportunity to take advantage of D's metaprogramming capabilities. Start with `__traits(allMembers, std.math)` and go from there. T -- Why is it that all of the instruments seeking intelligent life in the universe are pointed away from Earth? -- Michael Beibl
Aug 14 2020
On 8/14/2020 9:28 PM, mw wrote:I list 8 things I've found below. Suggestions or PR welcome, e.g. even on how to improve the current implementation of `struct Checked`, or help from the compiler.This is nice work. Thank you! Please file these issues in Bugzilla.
Aug 16 2020
On Sunday, 16 August 2020 at 23:36:51 UTC, Walter Bright wrote:On 8/14/2020 9:28 PM, mw wrote:filed here: https://issues.dlang.org/show_bug.cgi?id=21169I list 8 things I've found below. Suggestions or PR welcome, e.g. even on how to improve the current implementation of `struct Checked`, or help from the compiler.This is nice work. Thank you! Please file these issues in Bugzilla.
Aug 17 2020
On Mon, Aug 17, 2020 at 05:10:01PM +0000, mw via Digitalmars-d wrote:On Sunday, 16 August 2020 at 23:36:51 UTC, Walter Bright wrote:You might want to consider splitting up that bug into multiple smaller, more self-contained bugs. Less intimidating that way for potential contributors to fix. ;-) T -- This sentence is false.On 8/14/2020 9:28 PM, mw wrote:filed here: https://issues.dlang.org/show_bug.cgi?id=21169I list 8 things I've found below. Suggestions or PR welcome, e.g. even on how to improve the current implementation of `struct Checked`, or help from the compiler.This is nice work. Thank you! Please file these issues in Bugzilla.
Aug 17 2020
On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:On Mon, Aug 17, 2020 at 05:10:01PM +0000, mw via Digitalmars-d wrote:Was hesitating between splitting or not, then thought user may want to take the full picture into consideration the best approach to fix the issue, e.g. in case one-stone-that-can-kill-multiple-birds. (People can always submit separate a PR to fix one particular issue).https://issues.dlang.org/show_bug.cgi?id=21169You might want to consider splitting up that bug into multiple smaller, more self-contained bugs. Less intimidating that way for potential contributors to fix. ;-)Chain assignment fix: https://github.com/dlang/phobos/pull/7599Thanks 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; ```
Aug 17 2020
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:[...]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 you thought it does. So I'm not sure this case should be supported. Assigning from Checked back to native should always be explicit IMO (the programmer explicitly indicates he doesn't want Checked protections anymore). T -- If I were two-faced, would I be wearing this one? -- Abraham LincolnChain assignment fix: https://github.com/dlang/phobos/pull/7599Thanks 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; ```
Aug 17 2020
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: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.On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:[...]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 thoughChain assignment fix: https://github.com/dlang/phobos/pull/7599Thanks 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; ```you thought it does. So I'm not sure this case should be supported. Assigning from Checked back to native should always be explicit IMO (the programmer explicitly indicates he doesn't want Checked protections anymore).
Aug 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: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.On Mon, Aug 17, 2020 at 05:58:16PM +0000, mw via Digitalmars-d wrote: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.On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:[...]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 thoughChain assignment fix: > https://github.com/dlang/phobos/pull/7599Thanks 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; ```
Aug 17 2020
On Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote:On 8/17/20 4:53 PM, mw wrote:Right, the library fix (work-around) is sub-optimal, it's better be fixed by the compiler. Walter, it's your turn :-)On Monday, 17 August 2020 at 18:10:16 UTC, H. S. Teoh 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.On Mon, Aug 17, 2020 at 05:58:16PM +0000, mw via Digitalmars-d wrote: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.On Monday, 17 August 2020 at 17:15:59 UTC, H. S. Teoh wrote:[...]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 thoughChain assignment fix: > https://github.com/dlang/phobos/pull/7599Thanks 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; ```
Aug 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
Aug 17 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: [...]https://issues.dlang.org/show_bug.cgi?id=21175 Not holding my breath.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. ;-)
Aug 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
Aug 18 2020
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.
Mar 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: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.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.
Mar 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: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.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.
Mar 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:LHS I guessOn Tuesday, 18 August 2020 at 01:23:01 UTC, Andrei Alexandrescu wrote: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 RHSRequiring 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.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/
Mar 24 2021
On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined... I think the intent was to not force an order of execution of subexpressions on either side of a single assignment (e.g. a[i] = a[j] with an opIndex implementation), but this seems to leave too much leeway for assignment chains. Side note: having an undefined order of execution of the sides of an assignment can be a great source of fun (read: surprising) bugs in C++. Just going from GCC to clang switches the order around.
Mar 24 2021
On Wednesday, 24 March 2021 at 18:38:07 UTC, Gregor Mückl wrote:On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:Where is the spec you referring to? Let's fix the spec first then.Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...
Mar 24 2021
On Wednesday, 24 March 2021 at 18:38:07 UTC, Gregor Mückl wrote:On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:You're probably mistaken. Evaluation order does not mean associating an expression differently. Assignment is right associative in any case: a = b = c is the same as a = (b = c) but when *evaluating* a, b, and c, the compiler can choose to evaluate e.g. b first. It makes more sense if you look at functions retuning by `ref`: int _a, _b, _c; ref int a() { return _a; } ref int b() { return _b; } ref int c() { return _c; } Then, in (parentheses are optional in D) a() = (b() = c()) the compiler could execute b() first, a() second and c() last, getting references (i.e. pointers) and assigning them in the associated way.Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...
Mar 24 2021
On Wednesday, 24 March 2021 at 19:29:54 UTC, Q. Schroll wrote:On Wednesday, 24 March 2021 at 18:38:07 UTC, Gregor Mückl wrote:Right, I've made a mistake and confused order of evaluation and associativity in my first look at the spec. Oops :( Still, I think that this part the spec isn't actually well written. I'm mostly referring to the section on order of evaluation, but the rest of this page is also relevant: https://dlang.org/spec/expression.html#order-of-evaluation What I'm missing is a clear statement about operator associativity and operator precedence for expressions. When I'm reading the spec without applying any additional common sense, a + b * c could be evaluated strictly from left to right because I don't see how mathematical operator precedence is explicitly established anywhere. Neither do I see associativity established anywhere. If assignment was clearly defined to be right-associative, things would be unambiguous.On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:You're probably mistaken. Evaluation order does not mean associating an expression differently. Assignment is right associative in any case: a = b = c is the same as a = (b = c) but when *evaluating* a, b, and c, the compiler can choose to evaluate e.g. b first. It makes more sense if you look at functions retuning by `ref`: int _a, _b, _c; ref int a() { return _a; } ref int b() { return _b; } ref int c() { return _c; } Then, in (parentheses are optional in D) a() = (b() = c()) the compiler could execute b() first, a() second and c() last, getting references (i.e. pointers) and assigning them in the associated way.Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...
Mar 24 2021
On Wednesday, 24 March 2021 at 21:38:20 UTC, Gregor Mückl wrote:[...]I'd actually like my claim to be proven wrong. I just can't seem to accomplish that myself ;).
Mar 24 2021
On 24.03.21 22:38, Gregor Mückl wrote:What I'm missing is a clear statement about operator associativity and operator precedence for expressions. When I'm reading the spec without applying any additional common sense, a + b * c could be evaluated strictly from left to right because I don't see how mathematical operator precedence is explicitly established anywhere. Neither do I see associativity established anywhere. If assignment was clearly defined to be right-associative, things would be unambiguous.It's in the grammar. `a + b * c` is parsed as (skipping the boring parts): AddExpression "a" "+" MulExpression "b" "*" "c" And `a = b = c`: AssignExpression "a" "=" AssignExpression "b" "=" "c"
Mar 24 2021
On Wed, Mar 24, 2021 at 06:38:07PM +0000, Gregor Mückl via Digitalmars-d wrote:On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:Link to spec please? If what you say is true, that sounds like an error in the spec. Walter has said many times that evaluation order in D is left to right, unless otherwise indicated. Having it unspecified just leads to a huge can o' worms. [...]Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...Side note: having an undefined order of execution of the sides of an assignment can be a great source of fun (read: surprising) bugs in C++. Just going from GCC to clang switches the order around.Exactly, this is why Walter is against having unspecific order of execution. This supposed "optimization opportunity" leads to far more trouble than it's worth. T -- What doesn't kill me makes me stranger.
Mar 24 2021
On Wednesday, 24 March 2021 at 21:28:24 UTC, H. S. Teoh wrote:On Wed, Mar 24, 2021 at 06:38:07PM +0000, Gregor Mückl via Digitalmars-d wrote:See point 1 under "Implementation Defined": https://dlang.org/spec/expression.html#order-of-evaluation "The order of evaluation of the operands of AssignExpression."On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:Link to spec please? If what you say is true, that sounds like an error in the spec. Walter has said many times that evaluation order in D is left to right, unless otherwise indicated. Having it unspecified just leads to a huge can o' worms.Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...
Mar 24 2021
On Wed, Mar 24, 2021 at 09:40:07PM +0000, Gregor Mückl via Digitalmars-d wrote:On Wednesday, 24 March 2021 at 21:28:24 UTC, H. S. Teoh wrote:The keyword here is "operands". The order of evaluation of the *operands* is implementation-defined; the order of the evaluation of the assignment *operators* is from right to left. T -- Only boring people get bored. -- JMOn Wed, Mar 24, 2021 at 06:38:07PM +0000, Gregor Mückl via Digitalmars-d wrote:See point 1 under "Implementation Defined": https://dlang.org/spec/expression.html#order-of-evaluation "The order of evaluation of the operands of AssignExpression."On Wednesday, 24 March 2021 at 17:38:14 UTC, H. S. Teoh wrote:Link to spec please? If what you say is true, that sounds like an error in the spec. Walter has said many times that evaluation order in D is left to right, unless otherwise indicated. Having it unspecified just leads to a huge can o' worms.Since there is only one sensible meaning of `a = b = c`...If I'm reading the spec on expressions right, the compiler is actually free to interpret that as (a = b) = c if it feels particularly adventurous. The evaluation order of assignment operations is explicitly undefined...
Mar 24 2021
On Mon, Aug 17, 2020 at 05:10:01PM +0000, mw via Digitalmars-d wrote: [...]https://issues.dlang.org/show_bug.cgi?id=21169Chain assignment fix: https://github.com/dlang/phobos/pull/7599 T -- Some days you win; most days you lose.
Aug 17 2020
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.
Mar 24 2021