www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - bug : consecutive function calls and -inline

reply noob-is-noob <noob gmail.com> writes:
sorry if it has been discussed.
===code===
module evbug ;
import std.stdio ;

struct S(T) {
  T[] arr ;
  S!(T) opCall(T a) {
    arr ~= a ;
    writefln("%s ", arr) ;
    return *this ;
  }
}

void main() {
  S!(string) t ;
  t("AAA")("BBB")("CCC") ;
  t("<-result") ;
}
===output=== v2.014 (similar result for v1.030)
1/ compiled with -inline, ok:
[AAA]
[AAA BBB]
[AAA BBB CCC]
[AAA BBB CCC <-result]

2/ compiled w/o -inline, ng:
[AAA]
[AAA BBB]
[AAA BBB CCC]
[AAA <-result]
May 23 2008
next sibling parent reply janderson <askme me.com> writes:
noob-is-noob wrote:
 sorry if it has been discussed.
 ===code===
 module evbug ;
 import std.stdio ;

 struct S(T) {
   T[] arr ;
   S!(T) opCall(T a) {
     arr ~= a ;
     writefln("%s ", arr) ;
     return *this ;
   }
 }

 void main() {
   S!(string) t ;
   t("AAA")("BBB")("CCC") ;
   t("<-result") ;
 }
 ===output=== v2.014 (similar result for v1.030)
 1/ compiled with -inline, ok:
 [AAA]
 [AAA BBB]
 [AAA BBB CCC]
 [AAA BBB CCC <-result]

 2/ compiled w/o -inline, ng:
 [AAA]
 [AAA BBB]
 [AAA BBB CCC]
 [AAA <-result]


It seems slightly odd that your implicitly copying T[]. I wonder if there's even a defined behavior for copying of array indirectly by struct. I'd imagine that what the second version is doing is copying the structure each time while the first is not. So: T[] a; a.length = 10; ... T[] b; b.length = a.length; b.ptr = a.ptr; b.length += 5; T[] c; c.length = b.length; c.ptr = b.ptr; c.length += 5; //a.length is 10 //b.length is 15 //c.length is 20 Now we try to modify the first element again (which is what your doing). a.length += 5; //a.length is now 15 //b.length is still 15 //c.length is still 20 It maybe that the second version is the correct behavior. Maybe the compiler shouldn't let you copy structs implicitly if you have pointers or arrays in them. Tip. Try using pointers or a class. How that helps. -Joel
May 24 2008
parent reply noob-is-noob <noob gmail.com> writes:
janderson wrote:
 noob-is-noob wrote:
 sorry if it has been discussed.
 <snip old code>



It seems slightly odd that your implicitly copying T[]. I wonder if there's even a defined behavior for copying of array indirectly by struct. I'd imagine that what the second version is doing is copying the structure each time while the first is not. So: < snip old code > How that helps. -Joel

Thank you. But it seems not related to array copying. I've tried with a more basic data type. ==code== import std.stdio ; class A { int c = 0 ; A opCall(int b) { c = c + b ; writefln(c) ; return this ; } } struct B { int c = 0 ; B opCall(int b) { c = c + b ; writefln(c) ; return *this ; } } void main() { A a = new A ; B b ; a(1)(2)(3) ; a(0) ; b(1)(2)(3) ; b(0) ; } ==output=== (edited) -inline version: 1 3 6 6 <- class A 1 3 6 6 <- struct B non-inline version: 1 3 6 6 <- class A 1 3 6 1 <- struct B sorry for my bad English.
May 24 2008
next sibling parent Sivo Schilling <sivo.schilling web.de> writes:
noob-is-noob Wrote:

 janderson wrote:
 noob-is-noob wrote:
 sorry if it has been discussed.
 <snip old code>



It seems slightly odd that your implicitly copying T[]. I wonder if there's even a defined behavior for copying of array indirectly by struct. I'd imagine that what the second version is doing is copying the structure each time while the first is not. So: < snip old code > How that helps. -Joel

Thank you. But it seems not related to array copying. I've tried with a more basic data type. ==code== import std.stdio ; class A { int c = 0 ; A opCall(int b) { c = c + b ; writefln(c) ; return this ; } } struct B { int c = 0 ; B opCall(int b) { c = c + b ; writefln(c) ; return *this ; } } void main() { A a = new A ; B b ; a(1)(2)(3) ; a(0) ; b(1)(2)(3) ; b(0) ; } ==output=== (edited) -inline version: 1 3 6 6 <- class A 1 3 6 6 <- struct B non-inline version: 1 3 6 6 <- class A 1 3 6 1 <- struct B sorry for my bad English.

the struct in your code with a pointer to a struct it works. Ok it looks ugly but you can use opCall only on structs not pointer to structs. ===code=== module structptr; import std.stdio; struct S { int c; S* opCall(int cc) { c += cc; writef(c, " "); return this; } } void main() { // use an S on the heap auto t = new S; (*(*(*t)(1))(2))(3); (*t)(0); writefln("\n========"); // use an S on the stack S s; S* sp = &s; (*(*(*sp)(1))(2))(3); (*sp)(0); } ===end of code=== output (compiled without -inline !): 1 3 6 6 ======== 1 3 6 6 as expected. With classes you don't go into such problems because they are always references to heap or stack allocated memory. Regards.
May 24 2008
prev sibling parent janderson <askme me.com> writes:
noob-is-noob wrote:
 janderson wrote:
 noob-is-noob wrote:
 sorry if it has been discussed.
 <snip old code>



there's even a defined behavior for copying of array indirectly by struct. I'd imagine that what the second version is doing is copying the structure each time while the first is not. So: < snip old code > How that helps. -Joel

Thank you. But it seems not related to array copying. I've tried with a more basic data type. ==code== import std.stdio ; class A { int c = 0 ; A opCall(int b) { c = c + b ; writefln(c) ; return this ; } } struct B { int c = 0 ; B opCall(int b) { c = c + b ; writefln(c) ; return *this ; } } void main() { A a = new A ; B b ; a(1)(2)(3) ; a(0) ; b(1)(2)(3) ; b(0) ; } ==output=== (edited) -inline version: 1 3 6 6 <- class A 1 3 6 6 <- struct B non-inline version: 1 3 6 6 <- class A 1 3 6 1 <- struct B sorry for my bad English.

Your right about that. Length in an array is simply like a int. That is an array is: struct Array(T) { uint Length; T* t; } so if you put that in your struct you get: struct MyStruct { uint Length; //This T* t; } My point is that it is more bug prone when you start having different lengths pointing to the same array. The other thing is that when you exceed a the available memory in the slot the array was allocated, t will change in that one place to a new location. It won't change in any of the other copies. You might also try a pointer to an array. -Joel
May 24 2008
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
noob-is-noob wrote:
 sorry if it has been discussed.
 ===code===
 module evbug ;
 import std.stdio ;
 
 struct S(T) {
   T[] arr ;
   S!(T) opCall(T a) {
     arr ~= a ;
     writefln("%s ", arr) ;
     return *this ;
   }
 }
 
 void main() {
   S!(string) t ;
   t("AAA")("BBB")("CCC") ;
   t("<-result") ;
 }
 ===output=== v2.014 (similar result for v1.030)
 1/ compiled with -inline, ok:
 [AAA]
 [AAA BBB]
 [AAA BBB CCC]
 [AAA BBB CCC <-result]
 
 2/ compiled w/o -inline, ng:
 [AAA]
 [AAA BBB]
 [AAA BBB CCC]
 [AAA <-result]

This definitely looks like a bug to me. However, the second behavior (w/o -inline) is the correct one. opCall returns a *copy* of the struct it's called on, so only the initial call in each sequence should modify the original. The other two should modify copies. That means only "AAA" and "<-result" should be in t.arr at the end of main(). Since GDC gets this right, it's probably a bug in the DMD inliner. I've entered this into bugzilla: <http://d.puremagic.com/issues/show_bug.cgi?id=2127>
May 24 2008
parent noob-is-noob <noob gmail.com> writes:
Frits van Bommel wrote:
 noob-is-noob wrote:
 <snip>

This definitely looks like a bug to me. However, the second behavior (w/o -inline) is the correct one. opCall returns a *copy* of the struct it's called on, so only the initial call in each sequence should modify the original. The other two should modify copies. That means only "AAA" and "<-result" should be in t.arr at the end of main(). Since GDC gets this right, it's probably a bug in the DMD inliner. I've entered this into bugzilla: <http://d.puremagic.com/issues/show_bug.cgi?id=2127>

Thank you. I take janderson's advice, change to use class, and avoid return struct *this.
May 24 2008