Order of evaluation for named arguments

Timon Gehr timon.gehr at gmx.ch
Thu Apr 3 17:08:57 UTC 2025


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'.
> ...

I disagree. It's different from C#/Python/... for _no good reason_. It's 
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.


More information about the Digitalmars-d mailing list