www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Chained method argument evaluation order

reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
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. 
Jan 16 2008
next sibling parent Sean Kelly <sean f4.ca> writes:
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
Jan 16 2008
prev sibling parent Jason House <jason.james.house gmail.com> writes:
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.
Jan 16 2008