Thread overview
bug : consecutive function calls and -inline
May 23, 2008
noob-is-noob
May 24, 2008
janderson
May 24, 2008
noob-is-noob
May 24, 2008
Sivo Schilling
May 24, 2008
janderson
May 24, 2008
Frits van Bommel
May 24, 2008
noob-is-noob
May 23, 2008
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 24, 2008
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
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
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
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
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.
> 
> 
I'm not sure that this will suitable to you but if you replace 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
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.
> 
> 

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