June 18, 2013
2013/6/18 monarch_dodra <monarchdodra@gmail.com>

> On Saturday, 8 June 2013 at 15:56:47 UTC, deadalnix wrote:
>
>> On Saturday, 8 June 2013 at 14:52:23 UTC, monarch_dodra wrote:
>>
>> Sound like a nice idiom. Why is the first set of () needed ? Can we change the grammar to remove them ?
>>
>
> I've been playing around with this idiom some more, and found some pretty serious limitations:
>
> # Scoped block:
> Using a lambda functions creates a new scope. Having a "true" labeled
> block, just like static ifs, should not create a new scope. This is
> relevant if you want to make sure a constructor or destructor is nothrow,
> for example (destructor could be handled via a simple attribute followed by
> a colon. eg:
>
> void foo()
> {
>     nothrow {
>         Sentinel s; //declare sentinel
>     }
>
>     code_goes_here
>
>     nothrow:
>         clean_up_goes_here_code
>         destructors_are_nothrow
> }
>
> A lambda would not allow these two constructs.
>

In D, variable declaration with default construction is always nothrow. So, enclosing the declaration of s by nothrow block is unnecessary.

For nothrow destruction, you can add following static assert in foo().

    static assert(__traits(compiles, ()nothrow{ Sentinel s; }), "Sentinel
dtor is not nothrow");

# Purity
> Because a lambda needs to access the frame, any function using the lambda
> trick can't be made pure:
> void foo(T)(T a) @safe
> {
>     (){
>         ++a;
>     }();
> }
> Error: pure function 'main.foo' cannot call impure function literal
> '__lambda1'
>
> The workaround is to explicitly pass the arguments, *preferably*,
> shadowing them for clarity:
> void foo(int a) pure
> {
>     (ref int a){
>         ++a;
>     }(a);
> }
> This is already *much* less convenient. Imagine if the block needed to
> access 3, 5 or even more variabes ! Also, if one of those variables is
> declared as "auto", then you bring in the "ref typeof(a) a" ugliness. Just
> no.


This is a compiler bug, and I recently fixed it in git master. Explicit argument passing does not need anymore.


> # Performance
> I haven't actually tested this one, but I'd be inclined to think there is
> a performance hit for non-release and non-inline builds. inline builds
> *may* optimize it away, but I'm not sure...
>

Inlining should remove performance penalty. Nobody holds the immediately called lambda, so it should be treated as a 'scope delegate'. For that, we would need to add a section in language spec to support it.


> ----------------
> So my conclusion is that the lambda tric is a partial workaround. We'd need real support for being able to have specific qualification inside bodies.
>

I don't think so. We can sufficiently use lambda for the "attribute block".

Kenji Hara


June 18, 2013
On Tuesday, 18 June 2013 at 07:58:06 UTC, Kenji Hara wrote:
> In D, variable declaration with default construction is always nothrow.
> So, enclosing the declaration of s by nothrow block is unnecessary.

Well, what about construction with args...

> For nothrow destruction, you can add following static assert in foo().
>
>     static assert(__traits(compiles, ()nothrow{ Sentinel s; }), "Sentinel
> dtor is not nothrow");

Right. Good point.

> This is a compiler bug, and I recently fixed it in git master. Explicit
> argument passing does not need anymore.

Cool, thanks.

> Inlining should remove performance penalty. Nobody holds the immediately
> called lambda, so it should be treated as a 'scope delegate'. For that, we
> would need to add a section in language spec to support it.

Alright.

>> ----------------
>> So my conclusion is that the lambda tric is a partial workaround. We'd
>> need real support for being able to have specific qualification inside
>> bodies.
>>
>
> I don't think so. We can sufficiently use lambda for the "attribute block".
>
> Kenji Hara

Maybe you are right. I will keep using it for now.
June 18, 2013
On Saturday, 8 June 2013 at 14:57:17 UTC, monarch_dodra wrote:
> My beef though is that the syntax is a bit opaque, and not really idiomatic. It looks more like a hacker's trick than a real language feature. It's not something you'd do "naturally". At least, I know a beginner may not feal comfortable with this.
>
> Given that users are now actually doing this, that we have proof it works and is a useful feature, shouldn't we push to have actual blocks with attributes in the language?
>
> I think we should... Thoughts?

Here's my go at cleaning up the syntax a bit:
----
auto block(string attr)() {
    static struct Blk {
        mixin(q{
            void opBinary(string op:"in", T)(T dg) } ~ attr ~ q{
                if (is(typeof(() } ~ attr ~ q{ { dg(); }))) {
                dg();
            }
            void opBinary(string op:"in", T)(T dg) if (!is(typeof(() } ~ attr ~ ` { dg(); }))) {
                static assert(false, "Provided delegate is not " ~ "` ~ attr ~ `");
            }
        `);
    }
    return Blk();
}

void main() {
    // Works
    block!"nothrow" in {
        // Doesn't throw
    };

    // Fails
    block!"nothrow" in {
        throw new Exception("");
    };
}
----
Downsides are the required semicolon (needed for your method too) and abuse of operator overloading.
June 19, 2013
On Tuesday, 18 June 2013 at 08:10:24 UTC, monarch_dodra wrote:
>> Inlining should remove performance penalty. Nobody holds the immediately
>> called lambda, so it should be treated as a 'scope delegate'. For that, we
>> would need to add a section in language spec to support it.
>
> Alright.

I did some benching, and they aren't getting inline (well... I don't *think* they are): Code with an inline lambda call is definitely slower (in my case, with no args passed).

My tests are somewhat synthetic, (I'm testing a rather short function with a lambda) but the overall slowdown is quite noticeable. I don't worry about it much, but I guess these could scale in the grand scheme of things, and is a bit vexing when all you wanted to was mark something as trusted :/

Shouldn't an inlined lambda call *always* be... inlined? I really don't see a reason not to do so, but I'm outside my field of competence at that point.
June 30, 2013
On 06/18/2013 09:57 AM, Kenji Hara wrote:
>
>     # Purity
>     Because a lambda needs to access the frame, any function using the
>     lambda trick can't be made pure:
>     void foo(T)(T a) @safe
>     {
>          (){
>              ++a;
>          }();
>     }
>     Error: pure function 'main.foo' cannot call impure function literal
>     '__lambda1'
>
>     The workaround is to explicitly pass the arguments, *preferably*,
>     shadowing them for clarity:
>     void foo(int a) pure
>     {
>          (ref int a){
>              ++a;
>          }(a);
>     }
>     This is already *much* less convenient. Imagine if the block needed
>     to access 3, 5 or even more variabes ! Also, if one of those
>     variables is declared as "auto", then you bring in the "ref
>     typeof(a) a" ugliness. Just no.
>
>
> This is a compiler bug, and I recently fixed it in git master. Explicit
> argument passing does not need anymore.

Great. Does the fix also introduce the 'immutable' storage class for function literals for the case where a strongly pure literal is wanted?
July 01, 2013
On Sunday, 30 June 2013 at 20:29:07 UTC, Timon Gehr wrote:
>> This is a compiler bug, and I recently fixed it in git master. Explicit
>> argument passing does not need anymore.
>
> Great. Does the fix also introduce the 'immutable' storage class for function literals for the case where a strongly pure literal is wanted?

You may want to discuss that issue with Andrei. We had a discussion at DConf about this.
August 18, 2013
On Tuesday, 18 June 2013 at 07:58:06 UTC, Kenji Hara wrote:
> Inlining should remove performance penalty. Nobody holds the immediately
> called lambda, so it should be treated as a 'scope delegate'. For that, we
> would need to add a section in language spec to support it.

Kenji:

I've been doing some benchmarks recently: Using an "inlined lambda" seems to really kill performance, both with or without "-inline" (tested with both dmd and gdc).

However, using a named function, and then immediately calling it, there is 0 performance penalty (both w/ and w/o -inline).

Is this a bug? Can it be fixed? Should I file and ER?
August 19, 2013
2013/8/18 monarch_dodra <monarchdodra@gmail.com>

> On Tuesday, 18 June 2013 at 07:58:06 UTC, Kenji Hara wrote:
>
>> Inlining should remove performance penalty. Nobody holds the immediately called lambda, so it should be treated as a 'scope delegate'. For that, we would need to add a section in language spec to support it.
>>
>
> Kenji:
>
> I've been doing some benchmarks recently: Using an "inlined lambda" seems to really kill performance, both with or without "-inline" (tested with both dmd and gdc).
>
> However, using a named function, and then immediately calling it, there is 0 performance penalty (both w/ and w/o -inline).
>
> Is this a bug? Can it be fixed? Should I file and ER?
>

I opened a new bugzilla issue: http://d.puremagic.com/issues/show_bug.cgi?id=10848

And start working for the compiler and doc fix: https://github.com/D-Programming-Language/dlang.org/pull/372 https://github.com/D-Programming-Language/dmd/pull/2483

Kenji Hara


August 19, 2013
On Monday, 19 August 2013 at 02:33:43 UTC, Kenji Hara wrote:
> 2013/8/18 monarch_dodra <monarchdodra@gmail.com>
>
>> On Tuesday, 18 June 2013 at 07:58:06 UTC, Kenji Hara wrote:
>>
>>> Inlining should remove performance penalty. Nobody holds the immediately
>>> called lambda, so it should be treated as a 'scope delegate'. For that, we
>>> would need to add a section in language spec to support it.
>>>
>>
>> Kenji:
>>
>> I've been doing some benchmarks recently: Using an "inlined lambda" seems
>> to really kill performance, both with or without "-inline" (tested with
>> both dmd and gdc).
>>
>> However, using a named function, and then immediately calling it, there is
>> 0 performance penalty (both w/ and w/o -inline).
>>
>> Is this a bug? Can it be fixed? Should I file and ER?
>>
>
> I opened a new bugzilla issue:
> http://d.puremagic.com/issues/show_bug.cgi?id=10848
>
> And start working for the compiler and doc fix:
> https://github.com/D-Programming-Language/dlang.org/pull/372
> https://github.com/D-Programming-Language/dmd/pull/2483
>
> Kenji Hara

As always, thank you *very* much.
1 2
Next ›   Last »