www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - Chaining Bug

reply John Demme <me teqdruid.com> writes:
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;
  }
}
----------------------
Aug 09 2005
next sibling parent reply "Uwe Salomon" <post uwesalomon.de> writes:
 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
Aug 09 2005
parent Stewart Gordon <smjg_1998 yahoo.com> writes:
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.
Aug 09 2005
prev sibling parent John Demme <me teqdruid.com> writes:
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.

Aug 09 2005