Thread overview
Chaining Bug
Aug 09, 2005
John Demme
Aug 09, 2005
Uwe Salomon
Aug 09, 2005
Stewart Gordon
Aug 09, 2005
John Demme
August 09, 2005
The following code outputs "0" instead of "5" on DMD 0.129 on Linux. This is preventing chaining from working properly in my new containers library in some cases.

------------------
import std.stdio;

void main() {
  A a = new A;
  int val;
  a.foo(val).bar(val);
}

class A {

  A foo(out int val) {
    val = 5;
    return this;
  }

  A bar(int val) {
    writefln("%d", val);
    return this;
  }
}
----------------------

August 09, 2005
> The following code outputs "0" instead of "5" on DMD 0.129 on Linux.
> This is preventing chaining from working properly in my new containers
> library in some cases.
>
> ------------------
> import std.stdio;
>
> void main() {
>   A a = new A;
>   int val;
>   a.foo(val).bar(val);
> }
>
> class A {
>  A foo(out int val) {
>     val = 5;
>     return this;
>   }
>  A bar(int val) {
>     writefln("%d", val);
>     return this;
>   }
> }
> ----------------------

This is very interesting. The following assembler code is generated for the chained call:

#########
; Initialize out parameter val with 0.
xor	ECX,ECX
mov	-4[EBP],ECX

; Push the value of val.
push	ECX

; Push the address of val.
lea	EDX,-4[EBP]
push	EDX

; Call foo()
mov	EBX,[EAX]
call	dword ptr 018h[EBX]

; Call bar()
mov	ESI,[EAX]
call	dword ptr 01Ch[ESI]
###########

As you can see, the values for chained calls are already accumulated on the stack. Not sure if this is even desired behaviour... I remember reading something like "It is illegal to rely on the evaluation behaviour of function parameters" in the specs, which would apply to things like this:

###
callSomeFunc(i, ++i);
###

Perhaps this rule is extended to all parameters in a call chain?

Anyways, you could fix your library by passing the value as inout into bar.

Ciao
uwe
August 09, 2005
Uwe Salomon wrote:
<snip>
> As you can see, the values for chained calls are already accumulated on  the stack. Not sure if this is even desired behaviour... I remember  reading something like "It is illegal to rely on the evaluation behaviour  of function parameters" in the specs, which would apply to things like  this:
> 
> ###
> callSomeFunc(i, ++i);
> ###
> 
> Perhaps this rule is extended to all parameters in a call chain?

It's just one case of the rule.  The dependency structure is like this

    a        &val
    |       |    |
    a.foo(val)   val
        |         |
    a.foo(val).bar(val)

and so the compiler has the right to evaluate val before it evaluates a.foo(val).  The only way to force evaulation order is to use separate statements or, where possible, a comma operator.

> Anyways, you could fix your library by passing the value as inout into bar.

It took me a moment to see how it would help....

Stewart.

-- 
My e-mail is valid but not my primary mailbox.  Please keep replies on on the 'group where everyone may benefit.
August 09, 2005
Well, I guess I got burned there.  I expected if it was something like this, that it would only happen if I compiled with -O, so I tried it both ways.

I guess I'll just change it to inout.

On Tue, 2005-08-09 at 17:50 +0100, Stewart Gordon wrote:
> Uwe Salomon wrote:
> <snip>
> > As you can see, the values for chained calls are already accumulated on the stack. Not sure if this is even desired behaviour... I remember reading something like "It is illegal to rely on the evaluation behaviour  of function parameters" in the specs, which would apply to things like  this:
> > 
> > ###
> > callSomeFunc(i, ++i);
> > ###
> > 
> > Perhaps this rule is extended to all parameters in a call chain?
> 
> It's just one case of the rule.  The dependency structure is like this
> 
>      a        &val
>      |       |    |
>      a.foo(val)   val
>          |         |
>      a.foo(val).bar(val)
> 
> and so the compiler has the right to evaluate val before it evaluates a.foo(val).  The only way to force evaulation order is to use separate statements or, where possible, a comma operator.
> 
> > Anyways, you could fix your library by passing the value as inout into bar.
> 
> It took me a moment to see how it would help....
> 
> Stewart.
>