View mode: basic / threaded / horizontal-split · Log in · Help
January 16, 2008
Chained method argument evaluation order
Something tells me this was discussed before, but sheesh..

int a() { Stdout.formatln("A"); return 1; }
int b() { Stdout.formatln("B"); return 2; }

struct S
{
   S* chain(int x)
   {
       Stdout.formatln("{}", x);
       return this;
   }
}

void main()
{
   S s;
   s.chain(a()).chain(b());
}

This prints the following compiled with DMDWin:

B
A
1
2

Notice that the chained methods are called in the right order, but that 
their arguments -- even though they're in different function calls!! -- are 
evaluated in _reverse_ order, and _before_ any of the chained methods are 
called.

I really wouldn't have expected this.  I _would_ have expected

A
1
B
2

But the compiler must be being clever here, for some reason.

Should this kind of thing be documented, specified, implementation-dependent 
etc.?  Because I would have expected the chained call above to basically be 
evaluated as:

auto t = s.chain(a());
t.chain(b());

which gives the expected output above.
January 16, 2008
Re: Chained method argument evaluation order
Jarrett Billingsley wrote:
> Something tells me this was discussed before, but sheesh..
> 
> int a() { Stdout.formatln("A"); return 1; }
> int b() { Stdout.formatln("B"); return 2; }
> 
> struct S
> {
>     S* chain(int x)
>     {
>         Stdout.formatln("{}", x);
>         return this;
>     }
> }
> 
> void main()
> {
>     S s;
>     s.chain(a()).chain(b());
> }
> 
> This prints the following compiled with DMDWin:
> 
> B
> A
> 1
> 2
> 
> Notice that the chained methods are called in the right order, but that 
> their arguments -- even though they're in different function calls!! -- are 
> evaluated in _reverse_ order, and _before_ any of the chained methods are 
> called.
> 
> I really wouldn't have expected this.  I _would_ have expected
> 
> A
> 1
> B
> 2
> 
> But the compiler must be being clever here, for some reason.
> 
> Should this kind of thing be documented, specified, implementation-dependent 
> etc.?

I think this is actually documented here:

http://www.digitalmars.com/d/1.0/expression.html

In the "Expression Order" section.  Basically, I think that:

a.op(b).op(c)

is equivalent to:

(a + b) + c

In terms of evaluation.  ie. I think you can be sure that the a.op(b)
function will be called first and that b will be evaluated before this
call takes place, but that's it.  The compiler is free to evaluate b and
c both before this call, and to do so in any order.  However, I think
Walter is planning on changing this for 2.0.


Sean
January 17, 2008
Re: Chained method argument evaluation order
Jarrett Billingsley wrote:
> I really wouldn't have expected this.

I'd expect the calls to be done in an implementation-dependent order.  It
reminds me of stuff like "a = b++ + b++;" which is a classic example of
undefined behavior.
Top | Discussion index | About this forum | D home