www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Order of evaluation for named arguments

reply Steven Schveighoffer <schveiguy gmail.com> writes:
In the D spec, the function parameter [section on order of 
evaluation](https://dlang.org/spec/expression.html#order-calls) 
says:

 Arguments are evaluated left to right.
So a question was raised, what about named arguments, since those might not match the order of parameters? I decided to test: ```d import std.stdio; void foo(int a, int b) { writeln(i"a: $(a), b: $(b)"); } void main() { int x; foo(b: ++x, a: ++x); } ``` According to the spec, this should print "a: 2, b: 1", as the order of evaluation of the expression should go left to right. But the actual printout is "a: 1, b: 2". So the question is, should we modify the spec to reflect this, or would it be better to change the compiler to enforce this left-to-right evaluation rule? -Steve
Mar 29
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Saturday, 29 March 2025 at 18:38:31 UTC, Steven Schveighoffer 
wrote:
 In the D spec, the function parameter [section on order of 
 evaluation](https://dlang.org/spec/expression.html#order-calls) 
 says:

 Arguments are evaluated left to right.
So a question was raised, what about named arguments, since those might not match the order of parameters? I decided to test: ```d import std.stdio; void foo(int a, int b) { writeln(i"a: $(a), b: $(b)"); } void main() { int x; foo(b: ++x, a: ++x); } ``` According to the spec, this should print "a: 2, b: 1", as the order of evaluation of the expression should go left to right. But the actual printout is "a: 1, b: 2". So the question is, should we modify the spec to reflect this, or would it be better to change the compiler to enforce this left-to-right evaluation rule? -Steve
I dont read it as wrong, thats left to right at the callsite; which if the compiler did extra work to break named arguments changing the order of operations would be anti-feature
Mar 29
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Saturday, 29 March 2025 at 18:45:14 UTC, monkyyy wrote:
 I dont read it as wrong, thats left to right at the callsite; 
 which if the compiler did extra work to break named arguments 
 changing the order of operations would be anti-feature
No, it's the opposite. It takes the order based on the parameter order (at declaration), not the argument order (at the call site). I can agree that properly processing the arguments in written order could be more difficult to process in the compiler. But I don't know for sure. In any case, there is a mismatch between the spec and the implementation. -Steve
Mar 29
parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Saturday, 29 March 2025 at 21:25:17 UTC, Steven Schveighoffer 
wrote:
 On Saturday, 29 March 2025 at 18:45:14 UTC, monkyyy wrote:
 I dont read it as wrong, thats left to right at the callsite; 
 which if the compiler did extra work to break named arguments 
 changing the order of operations would be anti-feature
No, it's the opposite. It takes the order based on the parameter order (at declaration), not the argument order (at the call site). I can agree that properly processing the arguments in written order could be more difficult to process in the compiler. But I don't know for sure. In any case, there is a mismatch between the spec and the implementation. -Steve
This is a functional vs impertive distinction; math imagines arguments being reduced by algerbra and in that world the call site isnt relivent, but for a machine left to right at the call site is just it doing as told in order. And Im not saying extra work as in difficult, I mean it functionally the compiler would need to have extra step or do use more storage to make it *less expressive* then the lazy thing.
Mar 29
parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 29 March 2025 at 23:03:27 UTC, monkyyy wrote:
 This is a functional vs impertive distinction; math imagines 
 arguments being reduced by algerbra and in that world the call 
 site isnt relivent, but for a machine left to right at the call 
 site is just it doing as told in order.

 And Im not saying extra work as in difficult, I mean it 
 functionally the compiler would need to have extra step or do 
 use more storage to make it *less expressive* then the lazy 
 thing.
Monkyyy brought up an excellent mathematical point, which adds significant value to the discussion. While Timon provided a summary of the two possibilities, I believe that, given the mathematical foundations of programming, it would be more productive to build upon Monkyyy's perspective rather than approaching it solely from a pragmatic standpoint. SDB 79
Mar 30
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 29 March 2025 at 18:38:31 UTC, Steven Schveighoffer 
wrote:
 
 So the question is, should we modify the spec to reflect this, 
 or would it be better to change the compiler to enforce this 
 left-to-right evaluation rule?
Given these considerations, I think updating the specification is the more pragmatic approach. The specification could be amended to state:
 "Positional arguments are evaluated left to right. Named 
 arguments are evaluated in the order of formal parameter 
 declarations."
SDB 79
Mar 29
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
Adapting the specification rather than modifying the compiler 
requires less development effort and leaves the current compiler 
implementation (e.g., DMD, LDC, GDC) intact.

On Saturday, 29 March 2025 at 18:38:31 UTC, Steven Schveighoffer 
wrote:
  or would it be better to change the compiler to enforce this 
 left-to-right evaluation rule?
I changed my mind because qhile positional arguments follow a left-to-right evaluation rule, switching to parameter order for named arguments introduces a duality in the language. This could increase the learning curve and require developers to remember two distinct rules. 🫠 SDB 79
Mar 29
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 3/29/25 19:38, Steven Schveighoffer wrote:
 In the D spec, the function parameter [section on order of evaluation] 
 (https://dlang.org/spec/expression.html#order-calls) says:
 
 Arguments are evaluated left to right.
So a question was raised, what about named arguments, since those might not match the order of parameters? I decided to test: ```d import std.stdio; void foo(int a, int b) {    writeln(i"a: $(a), b: $(b)"); } void main() {    int x;    foo(b: ++x, a: ++x); } ``` According to the spec, this should print "a: 2, b: 1", as the order of evaluation of the expression should go left to right. But the actual printout is "a: 1, b: 2". So the question is, should we modify the spec to reflect this, or would it be better to change the compiler to enforce this left-to-right evaluation rule? -Steve
Fixing the compiler is better. Changing the spec is slightly easier.
Mar 29
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/29/2025 4:00 PM, Timon Gehr wrote:
 Fixing the compiler is better. Changing the spec is slightly easier.
I suspect this issue came about because it simply wasn't considered when adding named parameters, and it just fell out this way. Changing it, though, can silently break existing code which makes people unhappy. I suggest changing the spec. P.S. the reason D has a defined behavior for this is because C/C++ leave it implementation-defined.
Mar 30
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 30 March 2025 at 07:00:19 UTC, Walter Bright wrote:
 I suggest changing the spec.

 P.S. the reason D has a defined behavior for this is because 
 C/C++ leave it implementation-defined.
C++ does not support named arguments natively, so there’s no direct comparison. However, function arguments in C++ have unspecified evaluation order—it is implementation-defined. the function call, not in the order of parameters. ```C using System; class Program { static void Foo(int a, int b) { Console.WriteLine($"a: {a}, b: {b}"); } static void Main() { int x = 0; Foo(b: ++x, a: ++x); } } ```

 
 a: 2, b: 1
it should enforce left-to-right evaluation at the call site. However, modifying the spec would be the "easier" solution, but that would make D behave unpredictably compared to other languages. Given that Walter Bright tends to avoid complex changes, he will likely suggest updating the spec rather than enforcing left-to-right evaluation. But if D wants to be intuitive and SDB 79
Mar 30
parent reply Walter Bright <newshound2 digitalmars.com> writes:
In principle I agree with you, but on a pragmatic note this will silently break 
existing code.
Mar 30
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 30 March 2025 at 17:45:07 UTC, Walter Bright wrote:
 In principle I agree with you, but on a pragmatic note this 
 will silently break existing code.
It will also silently *fix* existing code that was written under the assumption that the spec was correct.
Mar 30
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 3/30/25 23:04, Paul Backus wrote:
 On Sunday, 30 March 2025 at 17:45:07 UTC, Walter Bright wrote:
 In principle I agree with you, but on a pragmatic note this will 
 silently break existing code.
It will also silently *fix* existing code that was written under the assumption that the spec was correct.
I am also just not a big fan of accident-driven language design where compiler bugs are codified into the spec.
Mar 31
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/31/2025 7:46 AM, Timon Gehr wrote:
 On 3/30/25 23:04, Paul Backus wrote:
 It will also silently *fix* existing code that was written under the 
 assumption that the spec was correct.
If they didn't realize their code was producing the wrong results before, I don't see how they'd realize it was producing correct results later.
 I am also just not a big fan of accident-driven language design where compiler 
 bugs are codified into the spec.
Breaking existing code has repeatedly driven people away from D. The difficulty with making this change is there's no way to detect if there is a conflict, unless there's an additional requirement that the arguments be pure.
Apr 01
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 4/1/25 20:58, Walter Bright wrote:
 
 I am also just not a big fan of accident-driven language design where 
 compiler bugs are codified into the spec.
Breaking existing code has repeatedly driven people away from D.
So does keeping existing broken behavior. x) Why do cautionary C++ tales apply elsewhere but not here? Anyway, e.g. DIP1000 deprecations are hardly comparable to what this is. The evaluation order used to be _not specified_... The spec plainly allowed for breaking code that depends on evaluation order! There are degrees to things, and tradeoffs. It's not black and white. Some benefits are more important than others, and some drawbacks are less important than others. In the end it is up to you, I just don't understand it.
Apr 01
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 4/1/2025 4:44 PM, Timon Gehr wrote:
 Why do cautionary C++ tales apply elsewhere but not here?
It all depends on the magnitude of the damage done. There are tradeoffs in everything, nothing is a pure win. D is full of compromises.
 The 
 evaluation order used to be _not specified_... The spec plainly allowed for 
 breaking code that depends on evaluation order!
Right. And that was when we were breaking existing code with every new release. We agreed a year or two ago to not continue doing that.
 There are degrees to things, and tradeoffs. It's not black and white. Some 
 benefits are more important than others, and some drawbacks are less important 
 than others.
Absolutely right. Most of my career is programming with implementation defined evaluation order - it's deeply ingrained in me to not rely on it. Implementation-defined also means inconsistency. But I propose to document the existing behavior, so it is consistent and reliable. Consistency is a valuable characteristic.
 In the end it is up to you, I just don't understand it.
If I may be so bold, I think you do understand it, you just don't agree with it :-)
Apr 02
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 4/2/25 21:57, Walter Bright wrote:
 On 4/1/2025 4:44 PM, Timon Gehr wrote:
 Why do cautionary C++ tales apply elsewhere but not here?
It all depends on the magnitude of the damage done. There are tradeoffs in everything, nothing is a pure win. D is full of compromises.
 The evaluation order used to be _not specified_... The spec plainly 
 allowed for breaking code that depends on evaluation order!
Right. And that was when we were breaking existing code with every new release. We agreed a year or two ago to not continue doing that. ...
That does not rule out fixing bugs, I hope.
 
 There are degrees to things, and tradeoffs. It's not black and white. 
 Some benefits are more important than others, and some drawbacks are 
 less important than others.
Absolutely right. Most of my career is programming with implementation defined evaluation order - it's deeply ingrained in me to not rely on it. Implementation-defined also means inconsistency. But I propose to document the existing behavior, so it is consistent and reliable. Consistency is a valuable characteristic. ...
Right. Documenting an inconsistency does not make it consistent. Language warts are death by a thousand cuts, they conspire together to make the language hostile to users.
 
 In the end it is up to you, I just don't understand it.
If I may be so bold, I think you do understand it, you just don't agree with it :-)
I simply do not understand what goes into the decision-making on this. There does not seem to be any consistent line or standard. It is certainly also true that I do not agree with it.
Apr 02
next sibling parent claptrap <clap trap.com> writes:
On Wednesday, 2 April 2025 at 20:14:48 UTC, Timon Gehr wrote:
 On 4/2/25 21:57, Walter Bright wrote:

 I simply do not understand what goes into the decision-making 
 on this. There does not seem to be any consistent line or 
 standard.
There's an easy hacky fix. That's the decision making process.
Apr 02
prev sibling parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 2 April 2025 at 20:14:48 UTC, Timon Gehr wrote:
 Right. Documenting an inconsistency does not make it 
 consistent. Language warts are death by a thousand cuts, they 
 conspire together to make the language hostile to users.
While I don't think the breakage argument is particularly strong, I don't consider this a 'language wart'. First of all, anyone who designs code to only work when the side effects in an argument list are executed in a particular order is, to put in Walter's terms, a 'no hire' for me. I'd consider the side effects to be unordered just like in C, and D's 'left-to-right' specification is simply a courtesy giving more consistent behavior across compilers. The same way D initializes `char` to 0xFF and `float` to nan not to be useful, but just as something more predictable than garbage memory. (Although I'm not a fan of this, I wish everything was 0 initialized by default).
 I am also just not a big fan of accident-driven language design 
 where compiler bugs are codified into the spec.
Second of all, this is not a right characterization. That specification was written before named arguments existed, and never explicitly stated whether the order was relative to the argument list at the call site or the formal parameter list. It didn't have to, since they'd always be the same. Updating it to say something different as a new feature enters the language is not the same as 'codifying a compiler bug in the spec'. Now you might say: even if the spec is not precise, clearly it was always intended that side effects are always executed in lexical order of the source code. But that brings me to the third point: Named arguments were explicitly designed to have equivalent behavior to struct initializers, so they could supersede them. And as mentioned before, struct initializers also use the order of the declaration for side effects. Same for array initializers. In fact, D is full of syntactic sugar for function calls (UFCS, property syntax, operator overloading) which in the end is always equivalent to the de-sugared function call. ```D import std.stdio: writeln; struct S { this(int x) {writeln("S(", x, ")");} auto opBinaryRight(string op)(T a) => this; } struct T { this(int x) {writeln("T(", x, ")");} } void main() { T(2) * S(1); // equivalent to S(1).opBinaryRight(T(2)); // prints: // S(1) // T(2) } ``` So changing the order of evaluation for named argument would be inconsistent with everything else in the language.
Apr 03
next sibling parent reply GrimMaple <grimmaple95 gmail.com> writes:
On Thursday, 3 April 2025 at 09:33:30 UTC, Dennis wrote:

On Thursday, 3 April 2025 at 09:33:30 UTC, Dennis wrote:
 initializes `char` to 0xFF and `float` to nan not to be useful, 
 but just as something more predictable
ayy lmao As a side note, it's probably wise to issue a warning when someone does 'no hire' stuff anyway, eg this code: ```d int t = 1; auto z = t++ + ++t; ``` Should explicitly state that: ``` Warning: variable `t` is modified several times within one sequence point, consider refactoring. ``` Same goes for named arguments (bonus point - it's the same mechanism and the same warning!) ```d var t = 1; foo(a: t++, b: t++); // Warning: variable `t` is modified several times within one sequence point, consider refactoring ```
Apr 03
next sibling parent Ogion <ogion.art gmail.com> writes:
On Thursday, 3 April 2025 at 12:40:54 UTC, GrimMaple wrote:
 As a side note, it's probably wise to issue a warning when 
 someone does 'no hire' stuff anyway, eg this code:
 ```d
 int t = 1;
 auto z = t++ + ++t;
 ```
 Should explicitly state that:
 ```
 Warning: variable `t` is modified several times within one 
 sequence point, consider refactoring.
 ```
Some newer languages don’t have increment/decrement expressions. These expressions are great for writing “clever” code, and nobody likes reading and debugging “clever” code. And in trivial cases, `i++` is not *that* much better than `i += 1` to justify the additional language complexity and potential for misuse. Maybe we could deprecate them altogether. But I imagine the pushback.
Apr 03
prev sibling parent matheus <matheus gmail.com> writes:
On Thursday, 3 April 2025 at 12:40:54 UTC, GrimMaple wrote:
 ...
 ```d
 int t = 1;
 auto z = t++ + ++t;
 ```
 Should explicitly state that:
 ```
 Warning: variable `t` is modified several times within one 
 sequence point, consider refactoring.
 ```
...
For me the real risk is here: import std; void foo(int a, int b){ writeln(a+b); } void main(){ int t = 1; t = 1; foo(t++,++t); t = 1; foo(++t,++t); t = 1; foo(t++,t++); } prints: 4 5 3 Yes I know the problem and the convention and even the appealing for some people with this pre / pos increment. But in college I felt the pain for poor people learning and programming for the first time and facing things like this. Matheus.
Apr 03
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 4/3/25 11:33, Dennis wrote:
 On Wednesday, 2 April 2025 at 20:14:48 UTC, Timon Gehr wrote:
 Right. Documenting an inconsistency does not make it consistent. 
 Language warts are death by a thousand cuts, they conspire together to 
 make the language hostile to users.
While I don't think the breakage argument is particularly strong, I don't consider this a 'language wart'. ...
incidental language complexity.
 First of all, anyone who designs code to only work when the side effects 
 in an argument list are executed in a particular order is, to put in 
 Walter's terms, a 'no hire' for me. I'd consider the side effects to be 
 unordered just like in C, and D's 'left-to-right' specification is 
 simply a courtesy giving more consistent behavior across compilers. The 
 same way D initializes `char` to 0xFF and `float` to nan not to be 
 useful, but just as something more predictable than garbage memory. 
 (Although I'm not a fan of this, I wish everything was 0 initialized by 
 default).
 ...
Therefore the breakage argument is really weak. Anyway, there are use cases where evaluating in source order is just more convenient for inspection e.g. logging.
 I am also just not a big fan of accident-driven language design where 
 compiler bugs are codified into the spec.
Second of all, this is not a right characterization. That specification was written before named arguments existed, and never explicitly stated whether the order was relative to the argument list at the call site or the formal parameter list. It didn't have to, since they'd always be the same. Updating it to say something different as a new feature enters the language is not the same as 'codifying a compiler bug in the spec'. Now you might say: even if the spec is not precise, clearly it was always intended that side effects are always executed in lexical order of the source code.
Yes, I am indeed saying that. At least that was what we had discussed on the newsgroup and what I had implemented in my frontend before the spec was updated with this abomination: https://dlang.org/spec/expression.html#order-of-evaluation
 But that brings me to the third point:
 
 Named arguments were explicitly designed to have equivalent behavior to 
 struct initializers, so they could supersede them. And as mentioned 
 before, struct initializers also use the order of the declaration for 
 side effects.
Which is bad.
 Same for array initializers.
Which is bad.
 In fact, D is full of 
 syntactic sugar for function calls (UFCS, property syntax, operator 
 overloading) which in the end is always equivalent to the de-sugared 
 function call.
 
 ```D
 import std.stdio: writeln;
 
 struct S {
      this(int x) {writeln("S(", x, ")");}
      auto opBinaryRight(string op)(T a) => this;
 }
 
 struct T {
      this(int x) {writeln("T(", x, ")");}
 }
 
 void main() {
      T(2) * S(1); // equivalent to S(1).opBinaryRight(T(2));
      // prints:
      // S(1)
      // T(2)
 }
 ```
 
 So changing the order of evaluation for named argument would be 
 inconsistent with everything else in the language.
Those are all language warts. So is the fact that for AssignExpression the order is still implementation-defined.
Apr 03
parent reply Dennis <dkorpel gmail.com> writes:
On Thursday, 3 April 2025 at 17:08:57 UTC, Timon Gehr wrote:
 Those are all language warts.
That's a fair position, but it changes some key facts. This is no longer about an accident in the implementation of the recently added named arguments being codified in the spec. Instead, it's cementing a de-facto standard from since the beginning of dmd. A bad standard, but it's not trivial to revert it everywhere. Given that we all seem to agree that argument evaluation order is more about convenience than being a key ingredient for correct programs, that should help you understand Walter's decision making.
Apr 03
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 4/3/25 20:28, Dennis wrote:
 On Thursday, 3 April 2025 at 17:08:57 UTC, Timon Gehr wrote:
 Those are all language warts.
That's a fair position, but it changes some key facts. This is no longer about an accident in the implementation of the recently added named arguments being codified in the spec.
I do not really think it is important if the accident is in the named argument implementation or in the thing that named arguments have been deliberately implemented to be consistent with. I also do not want to disparage any of the existing implementation efforts, the spec has been a moving target. This is simply about a commitment that had been made on the newsgroup _to change any the existing behavior deviating from left-to-right_ that has had only partial follow-through so far, and is now being walked back in the spec instead of just a simple: "we have not done it yet because it did not seem important enough and we prioritized other things".
 Instead, it's 
 cementing a de-facto standard from since the beginning of dmd. A bad 
 standard, but it's not trivial to revert it everywhere. Given that we 
 all seem to agree that argument evaluation order is more about 
 convenience than being a key ingredient for correct programs, that 
 should help you understand Walter's decision making.
No. If that is the reason, then why say it is about not breaking code. Anyway, one does not have to commit to doing it oneself or think it is important in order to agree it is a good thing to be done in general.
Apr 03
parent reply Dennis <dkorpel gmail.com> writes:
On Thursday, 3 April 2025 at 18:48:49 UTC, Timon Gehr wrote:
 This is simply about a commitment that had been made on the 
 newsgroup _to change any the existing behavior deviating from 
 left-to-right_ that has had only partial follow-through so far,
 and is now being walked back in the spec instead of just a 
 simple: "we have not done it yet because it did not seem 
 important enough and we prioritized other things".
I wasn't aware of that commitment, have any implementation changes been made since that? And do you have a link to the newsgroup thread?
Apr 03
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 4/3/25 21:26, Dennis wrote:
 On Thursday, 3 April 2025 at 18:48:49 UTC, Timon Gehr wrote:
 This is simply about a commitment that had been made on the newsgroup 
 _to change any the existing behavior deviating from left-to-right_ 
 that has had only partial follow-through so far,
 and is now being walked back in the spec instead of just a simple: "we 
 have not done it yet because it did not seem important enough and we 
 prioritized other things".
I wasn't aware of that commitment, have any implementation changes been made since that? And do you have a link to the newsgroup thread?
I only found these so far, unfortunately these do not seem as conclusive as I remember (because they usually talk specifically about "functions" and I suspect some functions are considered to be more function-like than other functions): TDPL, says function arguments are evaluated left-to-right on page 50. https://forum.dlang.org/thread/f0pvsn$1pju$1 digitalmars.com https://github.com/dlang/dlang.org/pull/6 https://lists.puremagic.com/pipermail/digitalmars-d/2011-December/118189.html https://forum.dlang.org/thread/ylgtwzvqnupnehipxayk forum.dlang.org https://forum.dlang.org/thread/vbpjyhxtjmtebnjmidyf forum.dlang.org AFAIU both my frontend and SDC went with strict source-order evaluation. That seems like the only sensible generalization of left-to-right function argument evaluation, but perhaps common sense is not so common after all.
Apr 03
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Thursday, April 3, 2025 3:33:30 AM MDT Dennis via Digitalmars-d wrote:
 First of all, anyone who designs code to only work when the side
 effects in an argument list are executed in a particular order
 is, to put in Walter's terms, a 'no hire' for me. I'd consider
 the side effects to be unordered just like in C, and D's
 'left-to-right' specification is simply a courtesy giving more
 consistent behavior across compilers.
Part of me thinks that we should have randomized the order of evalutation with every run of the compiler just to shake out code that relies on it. Having it be defined to be left-to-right certainly helps with consistency, but I completely agree that code shouldn't be relying on it - if nothing else, because it's a bad habit to get into given that there are other major languages which don't follow it. - Jonathan M Davis
Apr 03
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 4/3/25 19:19, Jonathan M Davis wrote:
 On Thursday, April 3, 2025 3:33:30 AM MDT Dennis via Digitalmars-d wrote:
 First of all, anyone who designs code to only work when the side
 effects in an argument list are executed in a particular order
 is, to put in Walter's terms, a 'no hire' for me. I'd consider
 the side effects to be unordered just like in C, and D's
 'left-to-right' specification is simply a courtesy giving more
 consistent behavior across compilers.
Part of me thinks that we should have randomized the order of evalutation with every run of the compiler just to shake out code that relies on it. Having it be defined to be left-to-right certainly helps with consistency, but I completely agree that code shouldn't be relying on it - if nothing else, because it's a bad habit to get into given that there are other major languages which don't follow it. - Jonathan M Davis
This is insane. Just don't allow any non-identifier arguments at that point.
Apr 03
prev sibling parent reply matheus <matheus gmail.com> writes:
On Tuesday, 1 April 2025 at 18:58:08 UTC, Walter Bright wrote:
 ...
 Breaking existing code has repeatedly driven people away from D.
 ...
I'm not saying you're wrong but is there any data about this? - I mean after "n" breakages we had a decrease in numbers of users? I pretty sure complains about breakages exists, as some developers leaved D community because restraint or DIP bureaucracy, but I think in the end most people would prefer a coherent language than another C++ one. Will users leave because this broke up software or fell safe that it follows a pattern? The problem I see with situation like this, is that we can't complain later when some streamer decide to use a language and show its problems for a large audience, and just after that people start to realize that we should have fixed this earlier. using System; public class Program{ public static int x; public static void foo(int a, int b){ Console.WriteLine("a: " + a + " b: " + b); } public static void Main(){ foo(b:++x,a:++x); } } Prints: a: 2 b: 1 So, arguments are evaluated left to right. Matheus.
Apr 02
parent Sergey <kornburn yandex.ru> writes:
On Wednesday, 2 April 2025 at 11:11:24 UTC, matheus wrote:
 On Tuesday, 1 April 2025 at 18:58:08 UTC, Walter Bright wrote:
 ...
 Breaking existing code has repeatedly driven people away from 
 D.
 ...
I'm not saying you're wrong but is there any data about this? - I mean after "n" breakages we had a decrease in numbers of users?
I'm not sure there was any estimation.. People were pissed off because of breaking tooling/projects every release.. I'm not sure how bad people will feel about breaking once a year with clear suggestions (semi-automatic scripts) of fixing breaking parts Seems not so many complaints in Rust/Zig.. and I think they have more production code than D (even Zig which is not even 1.0)
Apr 02
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Sunday, March 30, 2025 11:45:07 AM MDT Walter Bright via Digitalmars-d wrote:
 In principle I agree with you, but on a pragmatic note this will silently break
 existing code.
It might, but most folks don't even realize that named arguments are a thing in D, and most code doesn't rely on the order of evaluation of the arguments to a function. As such, I would expect that the amount of code that would actually break would be extremely small (and possibly zero). Most bug fixes risk silently breaking some piece of code that accidentally relied on the broken behavior, and I think this is a case where the odds of it actually causing problems are sufficiently low that it's worth just making it all consistent - and the sooner we do it, the less likely it is to break any code. - Jonathan M Davis
Mar 30
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 3/30/2025 6:21 PM, Jonathan M Davis wrote:
 It might, but most folks don't even realize that named arguments are a thing
 in D, and most code doesn't rely on the order of evaluation of the arguments
 to a function. As such, I would expect that the amount of code that would
 actually break would be extremely small (and possibly zero).
 
 Most bug fixes risk silently breaking some piece of code that accidentally
 relied on the broken behavior, and I think this is a case where the odds of
 it actually causing problems are sufficiently low that it's worth just
 making it all consistent - and the sooner we do it, the less likely it is to
 break any code.
It's a good argument, but we really have no idea how much code depends on named arguments. I'm also really tired of the vitriol we get when breaking existing code.
Apr 01
parent claptrap <clap trap.com> writes:
On Tuesday, 1 April 2025 at 19:00:49 UTC, Walter Bright wrote:
 On 3/30/2025 6:21 PM, Jonathan M Davis wrote:
 It might, but most folks don't even realize that named 
 arguments are a thing
 in D, and most code doesn't rely on the order of evaluation of 
 the arguments
 to a function. As such, I would expect that the amount of code 
 that would
 actually break would be extremely small (and possibly zero).
 
 Most bug fixes risk silently breaking some piece of code that 
 accidentally
 relied on the broken behavior, and I think this is a case 
 where the odds of
 it actually causing problems are sufficiently low that it's 
 worth just
 making it all consistent - and the sooner we do it, the less 
 likely it is to
 break any code.
It's a good argument, but we really have no idea how much code depends on named arguments. I'm also really tired of the vitriol we get when breaking existing code.
Will it be more or less vitriol than what you get from all the people who expect the arguments to be evaluated left to right? I mean there seems to be a pretty solid consensus that is what is expected. This fails pretty bad on the principle of least surprise right? And as it is now you have to look up the definition of the function to understand what order the arguments are evaluated. You cant know just by looking at the call code, you need to look at the function definition. It's unnecessary cognitive load, and unintuitive. And you will probably have to listen to people complain about it for years to come, just like the "strict private" crap. You want to have years and years of flame wars over argument evaluation order? Make the hard but correct decision.
Apr 01
prev sibling next sibling parent reply Daniel N <no public.email> writes:
On Saturday, 29 March 2025 at 18:38:31 UTC, Steven Schveighoffer 
wrote:
 In the D spec, the function parameter [section on order of 
 evaluation](https://dlang.org/spec/expression.html#order-calls) 
 says:

 Arguments are evaluated left to right.
So a question was raised, what about named arguments, since those might not match the order of parameters?
I think you are overlooking one important detail, StructInitializer, it must match named arguments and fortunately it does. ```d import std.stdio; struct S { int a, b; } int fun(int v) { v.writeln; return v; } void main() { S r; S s = { b:fun(1), a:fun(2) }; } ``` 2 1
Mar 30
next sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 30 March 2025 at 09:14:49 UTC, Daniel N wrote:
 I think you are overlooking one important detail, 
 StructInitializer, it must match named arguments and 
 fortunately it does.
It's a great perspective, but I don't think it's directly related to our topic. I've tried to increase the value below, but I haven't been successful in establishing relevance. 😇 ```d auto inc(T)(ref T value) { scope(exit) value.writeln; return ++value; } struct S { int a, b; } import std.stdio; void main() { auto x = 41; x.writeln; S s = { b : inc(x), a : inc(x) }; s.writeln; } ``` SDB 79
Mar 30
parent Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 30 March 2025 at 09:40:10 UTC, Salih Dincer wrote:
 ...I don't think it's directly related to our topic...
Like I said, there's no relevance/problem here. Because there is no ordering from the right or the left. The compiler selects and initials it according to the order in the struct. ```d enum fun = (int v) => v; S r = { b:fun(1), a:fun(2) }; r.writeln; // S(2, 1) ``` SDB 79
Mar 30
prev sibling parent reply Ogion <ogion.art gmail.com> writes:
On Sunday, 30 March 2025 at 09:14:49 UTC, Daniel N wrote:
 I think you are overlooking one important detail, 
 StructInitializer, it must match named arguments and 
 fortunately it does.


 ```d
 import std.stdio;
 struct S { int a, b; }

 int fun(int v)
 {
     v.writeln;
     return v;
 }

 void main()
 {
 	S r;
 	S s = { b:fun(1), a:fun(2) };
 }
 ```
 2
 1
Same with ArrayInitializer: ```D import std.stdio; int fun(int v) { v.writeln; return v; } void main() { int[2] a = [ 1:fun(1), 0:fun(2) ]; } ``` 1 2
Apr 01
parent Ogion <ogion.art gmail.com> writes:
On Tuesday, 1 April 2025 at 09:05:59 UTC, Ogion wrote:
 Same with ArrayInitializer:
  ```D
 import std.stdio;

 int fun(int v)
 {
     v.writeln;
     return v;
 }

 void main() {
 	int[2] a = [ 1:fun(1), 0:fun(2) ];
 }
 ```
 1
 2
Correction: 2 1
Apr 01
prev sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
I've been thinking about this situation for a few days.

I recognize that changing the compiler may not be a simple task.

My conclusion about the specification is that an attempt was made to 
define D so that the order of evaluation is always as written left to 
right. See comma expression for a near identical evaluation definition.

Before named arguments were added, the arguments list and parameter list 
orders matched, so a poorly written description was accurate.

However with named arguments the distinction between a called function 
parameter list dictating the matched argument list order, and the order 
as written by the user argument list, became meaningful.

It is my view that the order of evaluation should mirror that of the 
programmer, or at least be predictable. Named arguments entirely 
eliminate this predictability as a possibility as the order of 
evaluation could change over time or be in any position "unknown" to the 
user.

Right now the order in which arguments are written do not contribute to 
evaluation ordering. Although I suspect that this is more of an 
oversight then what is intended.

Regardless the spec here needs some work done to make this clearer, 
because it is confusing the called functions definition against the 
arguments list.
Mar 31
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 31 March 2025 at 19:47:01 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
 
 It is my view that the order of evaluation should mirror that 
 of the programmer, or at least be predictable. Named arguments 
 entirely eliminate this predictability as a possibility as the 
 order of evaluation could change over time or be in any 
 position "unknown" to the user.
+1 If the probability is low, as Jonathan emphasizes, then please change the behavior of the D compiler. Or if not, in this case, here is the intermediate solution: **Add a warning or error message** "Named arguments are evaluated in parameter order, so be mindful of side effects!" If this behavior is intentional, it at least needs to be clearly communicated. In summary, we cannot get away with changing the specification. Because this is an unintuitive situation. SDB 79
Mar 31
parent reply claptrap <clap trap.com> writes:
On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 On Monday, 31 March 2025 at 19:47:01 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 
 It is my view that the order of evaluation should mirror that 
 of the programmer, or at least be predictable. Named arguments 
 entirely eliminate this predictability as a possibility as the 
 order of evaluation could change over time or be in any 
 position "unknown" to the user.
+1 If the probability is low, as Jonathan emphasizes, then please change the behavior of the D compiler. Or if not, in this case, here is the intermediate solution: **Add a warning or error message** "Named arguments are evaluated in parameter order, so be mindful of side effects!"
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Mar 31
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Monday, 31 March 2025 at 23:16:57 UTC, claptrap wrote:
 On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 On Monday, 31 March 2025 at 19:47:01 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 [...]
+1 If the probability is low, as Jonathan emphasizes, then please change the behavior of the D compiler. Or if not, in this case, here is the intermediate solution: **Add a warning or error message** "Named arguments are evaluated in parameter order, so be mindful of side effects!"
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Doesnt that make the whole thing meaningless
Mar 31
parent reply claptrap <clap trap.com> writes:
On Tuesday, 1 April 2025 at 02:04:44 UTC, monkyyy wrote:
 On Monday, 31 March 2025 at 23:16:57 UTC, claptrap wrote:
 On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 On Monday, 31 March 2025 at 19:47:01 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 [...]
+1 If the probability is low, as Jonathan emphasizes, then please change the behavior of the D compiler. Or if not, in this case, here is the intermediate solution: **Add a warning or error message** "Named arguments are evaluated in parameter order, so be mindful of side effects!"
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Doesnt that make the whole thing meaningless
I thought the point was to document at call site, ie clarify long parameter lists, and enable skipping defaults? I mean I don't see the point of just being able to change the order the parameters are passed in?
Apr 01
next sibling parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:
 On Tuesday, 1 April 2025 at 02:04:44 UTC, monkyyy wrote:
 On Monday, 31 March 2025 at 23:16:57 UTC, claptrap wrote:
 On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 On Monday, 31 March 2025 at 19:47:01 UTC, Richard (Rikki) 
 Andrew Cattermole wrote:
 [...]
+1 If the probability is low, as Jonathan emphasizes, then please change the behavior of the D compiler. Or if not, in this case, here is the intermediate solution: **Add a warning or error message** "Named arguments are evaluated in parameter order, so be mindful of side effects!"
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Doesnt that make the whole thing meaningless
I thought the point was to document at call site, ie clarify long parameter lists, and enable skipping defaults? I mean I don't see the point of just being able to change the order the parameters are passed in?
Im still waiting on named argument templates disambiguation but im worried about expressiveness For example raylib has like 20 draw functions in a c verbose style; it be nice to overload them all; but oh no draw line and draw rectangle overlap (4 arguments, two x's and y's) in thoery after named argument works with templates you can redirect via parsing the .h defination easily
Apr 01
parent claptrap <clap trap.com> writes:
On Tuesday, 1 April 2025 at 12:04:36 UTC, monkyyy wrote:
 On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:

 Im still waiting on named argument templates disambiguation but 
 im worried about expressiveness

 For example raylib has like 20 draw functions in a c verbose 
 style; it be nice to overload them all; but oh no draw line and 
 draw rectangle overlap (4 arguments, two x's and y's)
why is having separate functions for drawLine, drawRect bad?
Apr 01
prev sibling next sibling parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:
 On Tuesday, 1 April 2025 at 02:04:44 UTC, monkyyy wrote:
 On Monday, 31 March 2025 at 23:16:57 UTC, claptrap wrote:
 On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 [...]
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Doesnt that make the whole thing meaningless
I thought the point was to document at call site, ie clarify long parameter lists, and enable skipping defaults? I mean I don't see the point of just being able to change the order the parameters are passed in?
It can happen that you change the order of parameter at the definition site. This should not require modiying all call sites with named arguments.
Apr 01
parent claptrap <clap trap.com> writes:
On Tuesday, 1 April 2025 at 17:13:45 UTC, Patrick Schluter wrote:
 On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:
 On Tuesday, 1 April 2025 at 02:04:44 UTC, monkyyy wrote:
 On Monday, 31 March 2025 at 23:16:57 UTC, claptrap wrote:
 On Monday, 31 March 2025 at 21:43:07 UTC, Salih Dincer wrote:
 [...]
Or just require that parameters are always passed in the same order as the declaration. Makes this bug impossible, and no *silent* breakage.
Doesnt that make the whole thing meaningless
I thought the point was to document at call site, ie clarify long parameter lists, and enable skipping defaults? I mean I don't see the point of just being able to change the order the parameters are passed in?
It can happen that you change the order of parameter at the definition site. This should not require modiying all call sites with named arguments.
It'd still break all call sites that don't use named parameters, maybe even silently if you're not careful. So its a thin argument IMO, changing the order of the parameters just seems like a bad idea, its just breakage, for nothing.
Apr 01
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:
 I mean I don't see the point of just being able to change the 
 order the parameters are passed in?
```d int generateNextThing(); // assume this is not easy to replicate void foo(int a, int b); void main() { // I want to pass the next thing in as b, and the next next thing in as a. auto bval = generateNextThing(); foo(generateNextThing(), bval); // hey, why not just pass them in the order specified! foo(b: generateNextThing(), a: generateNextThing()); // oops next thing goes to a, next next thing goes to b. } ``` It's not exactly a killer example, but you can see how one might expect that to work as the spec details. -Steve
Apr 01
parent claptrap <clap trap.com> writes:
On Wednesday, 2 April 2025 at 02:09:40 UTC, Steven Schveighoffer 
wrote:
 On Tuesday, 1 April 2025 at 11:26:34 UTC, claptrap wrote:
 I mean I don't see the point of just being able to change the 
 order the parameters are passed in?
```d int generateNextThing(); // assume this is not easy to replicate void foo(int a, int b); void main() { // I want to pass the next thing in as b, and the next next thing in as a. auto bval = generateNextThing(); foo(generateNextThing(), bval); // hey, why not just pass them in the order specified! foo(b: generateNextThing(), a: generateNextThing()); // oops next thing goes to a, next next thing goes to b. } ``` It's not exactly a killer example, but you can see how one might expect that to work as the spec details.
Ok yeah thats a good point.
Apr 02
prev sibling parent Salih Dincer <salihdb hotmail.com> writes:
In this case, the named arguments will have no meaning. It's such 
a thing that it sets you free; when you assign arguments default 
values. In the past, this facility did not exist and I used to 
feel very stuck.

SDB 79
Mar 31