Thread overview
An issue with lazy delegates
Jan 05, 2012
Andrej Mitrovic
Jan 07, 2012
Peter Alexander
Jan 07, 2012
Andrej Mitrovic
Jan 09, 2012
Stewart Gordon
January 05, 2012
import std.stdio;

void test(T)(lazy T dg)
{
    test2(dg);
}

void test2(T)(lazy T dg)
{
    dg();    // nothing happens
    dg()();  // have to use double-invocation instead
}

void main()
{
    test({ writeln("test"); });
}

Do you think it would be possible for the compiler to avoid wrapping delegates into another delegate? I'm having this problem with this sort of template:

import std.conv;
import std.string;

auto onFailThrow(E, T)(lazy T dg)
{
    try
    {
        static if (is(ReturnType!T == void))
            dg();
        else
            return dg();
    }
    catch (Exception ex)
    {
        throw new E(ex.msg);
    }
}

void main()
{
    string x = "x";
    string y = "y";
    onFailThrow!Exception({ to!int(x); });
    onFailThrow!Exception(to!int(y));
}

The first call doesn't do anything because the delegate is wrapped inside of another delegate. I want this template to be versatile enough to be used by both lazy expressions and delegate literals, but I don't know how.

If I write the same template but with "lazy" stripped off I'll have conflicting templates, but I don't know how I would write constraints to separate the two. Any ideas?
January 07, 2012
On 5/01/12 5:26 AM, Andrej Mitrovic wrote:
> The first call doesn't do anything because the delegate is wrapped
> inside of another delegate. I want this template to be versatile
> enough to be used by both lazy expressions and delegate literals, but
> I don't know how.

void test(T)(lazy T dg)
{
    static if (is(T == delegate))
        dg()();
    else
        dg();
}

void main()
{
    test( writeln("a") );
    test( { writeln("b"); } );
}
January 07, 2012
Hah, I never thought of using that check. Thanks.
January 09, 2012
On 05/01/2012 05:26, Andrej Mitrovic wrote:
<snip>
> The first call doesn't do anything because the delegate is wrapped
> inside of another delegate. I want this template to be versatile
> enough to be used by both lazy expressions and delegate literals, but
> I don't know how.
<snip>

If you have a delegate you want to use as a lazy expression, you can make the lazy argument a call to it

    onFailThrow!Exception({ to!int(x); }());

Of course, Peter's solution enables you to omit the () and just pass the delegate in, but it does mean that you can't lazily evaluate an expression to a delegate, unless you wrap it in a delegate literal.

Stewart.