www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Question of delegate literals and return from function(GDC,DMD,LDC)

reply amaury pouly <amaury.pouly gmail.com> writes:
Hello,
I have a little question about D: I want to have a function returning a
delegate and more precisely a delegate literal that uses one of the arguments
of the function. Here is an example:

int delegate(int) test(int[] tab)
{
    return (int d)
    {
        int sum;
        foreach(i;tab)
            sum+=i*d;// stupid computation
        return sum;
    };
}

int main()
{
    auto res=test([1,2,3,4,5,6])(4);
    return res;
}
Of course this example is stupid but the idea is here. The point is that if I
compile and run this code with DMD it works fine whereas it segfaults with GDC
and LDC(LLVM D). I also know a fix for the segfault with both GDC and LDC:

int delegate(int) test(int[] tab)
{
    struct Foo
    {
        int[] tab;
        
        int fn(int d)
        {
            int sum;
            foreach(i;tab)
                sum+=i*d;// stupid computation
            return sum;
        }
    }
    
    Foo *f=new Foo;
    f.tab=tab;
    return &f.fn;
}

int main()
{
    auto res=test([1,2,3,4,5,6])(4);
    return res;
}

My question is the following: is this a bug of GDC/LDC or is this the expected
behaviour ? The second solution must always work but I'm unsure about the first
one. Indeed, the specification says that a delegate shall not reference a stack
parameter which is logical but it says nothing about function arguments.
Jan 31 2009
next sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Sat, Jan 31, 2009 at 5:36 PM, amaury pouly <amaury.pouly gmail.com> wrot=
e:

 My question is the following: is this a bug of GDC/LDC or is this the exp=

the first one. Indeed, the specification says that a delegate shall not re= ference a stack parameter which is logical but it says nothing about functi= on arguments. In D1, returning nested functions from the function that defined them is undefined behavior. If you're using DMD1 and it's working, you just got lucky. The compilers could detect this better, but more generally it's a problem of escape analysis and there will always be cases where they get it wrong. But in D2, it's legal and will create a closure. If you're using DMD2, that's why it's working.
Jan 31 2009
prev sibling next sibling parent reply downs <default_357-line yahoo.de> writes:
amaury pouly wrote:
 Hello,
 I have a little question about D: I want to have a function returning a
delegate and more precisely a delegate literal that uses one of the arguments
of the function. Here is an example:
 
 int delegate(int) test(int[] tab)
 {
     return (int d)
     {
         int sum;
         foreach(i;tab)
             sum+=i*d;// stupid computation
         return sum;
     };
 }
 
 int main()
 {
     auto res=test([1,2,3,4,5,6])(4);
     return res;
 }

tools version: import tools.base, std.stdio; int delegate(int) test(int[] tab) { return tab /apply/ (int[] tab, int d) { int sum; foreach (i; tab) sum += i*d; return sum; }; } void main() { auto res = test([1,2,3,4,5,6])(4); writefln(res); }
Feb 01 2009
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
downs wrote:
 amaury pouly wrote:
 Hello,
 I have a little question about D: I want to have a function returning a
delegate and more precisely a delegate literal that uses one of the arguments
of the function. Here is an example:

 int delegate(int) test(int[] tab)
 {
     return (int d)
     {
         int sum;
         foreach(i;tab)
             sum+=i*d;// stupid computation
         return sum;
     };
 }

 int main()
 {
     auto res=test([1,2,3,4,5,6])(4);
     return res;
 }

tools version: import tools.base, std.stdio; int delegate(int) test(int[] tab) { return tab /apply/ (int[] tab, int d) { int sum; foreach (i; tab) sum += i*d; return sum; }; } void main() { auto res = test([1,2,3,4,5,6])(4); writefln(res); }

I was tempted to post mine out of sheer bloody-mindedness, except that it apparently doesn't work any more. Oh well, yours was about a million times safer, anyway. :P -- Daniel
Feb 01 2009
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
"amaury pouly" wrote
 Hello,
 I have a little question about D: I want to have a function returning a 
 delegate and more precisely a delegate literal that uses one of the 
 arguments of the function. Here is an example:

 int delegate(int) test(int[] tab)
 {
    return (int d)
    {
        int sum;
        foreach(i;tab)
            sum+=i*d;// stupid computation
        return sum;
    };
 }

 int main()
 {
    auto res=test([1,2,3,4,5,6])(4);
    return res;
 }
 Of course this example is stupid but the idea is here. The point is that 
 if I compile and run this code with DMD it works fine whereas it segfaults 
 with GDC and LDC(LLVM D). I also know a fix for the segfault with both GDC 
 and LDC:

 int delegate(int) test(int[] tab)
 {
    struct Foo
    {
        int[] tab;

        int fn(int d)
        {
            int sum;
            foreach(i;tab)
                sum+=i*d;// stupid computation
            return sum;
        }
    }

    Foo *f=new Foo;
    f.tab=tab;
    return &f.fn;
 }

 int main()
 {
    auto res=test([1,2,3,4,5,6])(4);
    return res;
 }

 My question is the following: is this a bug of GDC/LDC or is this the 
 expected behaviour ? The second solution must always work but I'm unsure 
 about the first one. Indeed, the specification says that a delegate shall 
 not reference a stack parameter which is logical but it says nothing about 
 function arguments.

Expected behavior. Function arguments *are* stack parameters. Even though you are passing a parameter whose storage is defined in the main function (and technically, is allocated on the heap), the 'tab' parameter to test is a stack-based struct which contains the pointer to the array. When main calls the delegate, it overwrites that struct with new data, because the stack frame is reused, and therefore, it's anyones guess why it works on dmd. -Steve
Feb 02 2009