Jump to page: 1 24  
Page
Thread overview
Can we fix this?
Sep 29, 2021
Imperatorn
Sep 29, 2021
jfondren
Sep 29, 2021
deadalnix
Sep 29, 2021
Imperatorn
Sep 29, 2021
jfondren
Sep 30, 2021
deadalnix
Sep 30, 2021
jfondren
Sep 30, 2021
Basile B.
Sep 30, 2021
Imperatorn
Sep 30, 2021
Tejas
Sep 30, 2021
deadalnix
Sep 30, 2021
Imperatorn
Sep 30, 2021
Max Samukha
Sep 29, 2021
jfondren
Sep 29, 2021
Elronnd
Sep 29, 2021
Imperatorn
Sep 29, 2021
jfondren
Sep 29, 2021
Imperatorn
Sep 30, 2021
deadalnix
Sep 30, 2021
Basile B.
Sep 30, 2021
jfondren
Sep 30, 2021
jfondren
Sep 30, 2021
deadalnix
Sep 30, 2021
Sebastiaan Koppe
Sep 30, 2021
bauss
Sep 30, 2021
Adam D Ruppe
Sep 30, 2021
bauss
Sep 30, 2021
deadalnix
Sep 30, 2021
Sebastiaan Koppe
Sep 30, 2021
deadalnix
Sep 30, 2021
deadalnix
Sep 30, 2021
deadalnix
Sep 30, 2021
deadalnix
Sep 30, 2021
deadalnix
Sep 30, 2021
Imperatorn
Sep 30, 2021
Max Samukha
Sep 30, 2021
deadalnix
September 29, 2021

https://issues.dlang.org/show_bug.cgi?id=2043

Impossible?

September 29, 2021

On Wednesday, 29 September 2021 at 10:44:53 UTC, Imperatorn wrote:

>

https://issues.dlang.org/show_bug.cgi?id=2043

Impossible?

... Documentation:

D has two kinds of blocks, the { ... } kind and the (){ ... }(); kind. Within the former, for efficiency, [something about this bug]. Within the latter, closure environments will be as expected from other languages at the cost of additional allocation. These "bubble blocks" are admittedly ugly but this is part of D's firm stand against the programming practices of the Scheme community.

void delegate()[] dgList;

void main() {
    import std.stdio : writeln;

    foreach(int i; [1, 2, 3]) {
        auto b = i+2;
        dgList ~= { writeln(b); };
        writeln(&b); // b will be the *same* on each iteration
    }
    foreach (dg; dgList)
        dg(); // output: 5 5 5
}

vs.

void delegate()[] dgList;

void main() {
    import std.stdio : writeln;

    foreach(int i; [1, 2, 3]) (){
        auto b = i+2;
        dgList ~= { writeln(b); };
        writeln(&b); // b will be *unique* on each iteration
    }();
    foreach (dg; dgList)
        dg(); // output: 3 4 5
}
September 29, 2021

On Wednesday, 29 September 2021 at 14:16:50 UTC, jfondren wrote:

>

On Wednesday, 29 September 2021 at 10:44:53 UTC, Imperatorn wrote:

>

https://issues.dlang.org/show_bug.cgi?id=2043

Impossible?

... Documentation:

D has two kinds of blocks, the { ... } kind and the (){ ... }(); kind.

No, the later is just a lambda, with a perfectly normal scope in it.

>

Within the former, for efficiency, [something about this bug].

Doing something fast and wrong is not exactly efficiency.

September 29, 2021

On Wednesday, 29 September 2021 at 14:34:01 UTC, deadalnix wrote:

>

On Wednesday, 29 September 2021 at 14:16:50 UTC, jfondren wrote:

>

On Wednesday, 29 September 2021 at 10:44:53 UTC, Imperatorn wrote:

>

https://issues.dlang.org/show_bug.cgi?id=2043

Impossible?

... Documentation:

D has two kinds of blocks, the { ... } kind and the (){ ... }(); kind.

No, the later is just a lambda, with a perfectly normal scope in it.

>

Within the former, for efficiency, [something about this bug].

Doing something fast and wrong is not exactly efficiency.

I'm still a bit confused. What is the recommended approach here? Should we fix the language or have best practices/documentation on how to "work around" the problem.

September 29, 2021

On Wednesday, 29 September 2021 at 16:23:34 UTC, Imperatorn wrote:

>

Should we

What 'we' have been doing for 13 years is to have this bugzilla link that documents the bug, and that it is a bug, with some commentary on it, including a workaround.

I'm not prepared to fix the bug, and per Lindy's Law the bug should get fixed in 2034, so my interest is

  1. I'd like to not get surprised by this bug,

  2. I'd like to have a reliable workaround for the bug.

And those would've been satisfied with documentation. Something that's been the case for 13 years should just be in the spec with its workaround. People read the spec and expect to know the language; they don't read all of bugzilla. It's not like it's hard to edit the spec when the bug is fixed.

Also, once you expect users to anticipate when they'll need the workaround, this objection becomes lighter: "People have made it clear they don't particularly like hidden allocations in innocuous looking code. Hence the genesis of the @nogc attribute. For this particular issue, it would be hard to look at a random loop and see if allocations are occurring - i.e. a nasty surprise if a small change suddenly made a big hit in performance. Profiling is not the answer, as very, very few people profile code."

As those random loops where allocations occur are precisely the loops that need the workaround.

>

fix the language or have best practices/documentation on how to "work around" the problem.

September 29, 2021

On 9/29/21 10:16 AM, jfondren wrote:

>

On Wednesday, 29 September 2021 at 10:44:53 UTC, Imperatorn wrote:

>

https://issues.dlang.org/show_bug.cgi?id=2043

Impossible?

... Documentation:

D has two kinds of blocks, the { ... } kind and the (){ ... }(); kind. Within the former, for efficiency, [something about this bug]. Within the latter, closure environments will be as expected from other languages at the cost of additional allocation. These "bubble blocks" are admittedly ugly but this is part of D's firm stand against the programming practices of the Scheme community.

void delegate()[] dgList;

void main() {
     import std.stdio : writeln;

     foreach(int i; [1, 2, 3]) {
         auto b = i+2;
         dgList ~= { writeln(b); };
         writeln(&b); // b will be the *same* on each iteration
     }
     foreach (dg; dgList)
         dg(); // output: 5 5 5
}

vs.

void delegate()[] dgList;

void main() {
     import std.stdio : writeln;

     foreach(int i; [1, 2, 3]) (){
         auto b = i+2;
         dgList ~= { writeln(b); };
         writeln(&b); // b will be *unique* on each iteration
     }();
     foreach (dg; dgList)
         dg(); // output: 3 4 5
}

This is not what I would have ever thought of, and it's kind of prone to error, since i is still used from within the lambda. It would not be hard to mess it up:

foreach(int i; [1, 2, 3]) (){
    dgList ~= { writeln(i + 2); }; // still outputs 5 5 5
}();

What we need is a syntax to specify which values are captured and which variables are referenced.

What I normally do if I need something like this is:

foreach(int i; [1, 2, 3]) {
   dgList ~= (b) { return {writeln(b);};} (i + 2);
   // or less error prone:
   dgList ~= (i) { return {writeln(i + 2);};} (i);
}

Which specifies the captured variable. But it's a lot of punctuation.

Some imagined syntax?

dgList ~= (@capture i) {writeln(i + 2);};
// or:
dgList ~= (@capture i) => writeln(i + 2);

-Steve

September 29, 2021

On Wednesday, 29 September 2021 at 16:47:23 UTC, Steven Schveighoffer wrote:

>
foreach(int i; [1, 2, 3]) {
   dgList ~= (b) { return {writeln(b);};} (i + 2);
   // or less error prone:
   dgList ~= (i) { return {writeln(i + 2);};} (i);
}

Which specifies the captured variable. But it's a lot of punctuation.

dgList ~= (i => { writeln(i + 2); })(i);

is cleaner, but ISRT that this usage will be banned because people rarely intend what it actually means.

I thought I tried this exact workaround and it didn't work, so I guessed that the optimizer had deleted the extra closure. But that does work, there.

>

Some imagined syntax?

dgList ~= (@capture i) {writeln(i + 2);};
// or:
dgList ~= (@capture i) => writeln(i + 2);

-Steve

Or a separate param list, to be similar to template params? (i)() { writeln(i + 2); };

Explicit captures are at least easy to explain since other languages have already gone this route.

September 29, 2021
On Wednesday, 29 September 2021 at 16:47:23 UTC, Steven Schveighoffer wrote:
> On 9/29/21 10:16 AM, jfondren wrote:
>> [...]
>
> This is not what I would have ever thought of, and it's kind of prone to error, since `i` is still used from within the lambda. It would not be hard to mess it up:
>
> ```d
> foreach(int i; [1, 2, 3]) (){
>     dgList ~= { writeln(i + 2); }; // still outputs 5 5 5
> }();
> ```
>
> What we need is a syntax to specify which values are captured and which variables are referenced.
>
> What I normally do if I need something like this is:
>
> ```d
> foreach(int i; [1, 2, 3]) {
>    dgList ~= (b) { return {writeln(b);};} (i + 2);
>    // or less error prone:
>    dgList ~= (i) { return {writeln(i + 2);};} (i);
> }
>
> ```
>
> Which specifies the captured variable. But it's a lot of punctuation.
>
> Some imagined syntax?
>
> ```d
> dgList ~= (@capture i) {writeln(i + 2);};
> // or:
> dgList ~= (@capture i) => writeln(i + 2);
> ```
>
> -Steve

Tbh I'd be for any change that could improve something.

But why can't we just do something minimal, like use what we have (commenting on imagined syntax)

(i) { /*use i here*/ } or
(i) => { /*use i here*/ }

Could we solve it without introducing attributes or reusing some?

Personally I'm used to the lambda expression so I wouldn't mind using that. But can we just do something more sane than what we currently have?

If I ask kindly?
September 29, 2021

On Wednesday, 29 September 2021 at 16:47:23 UTC, Steven Schveighoffer wrote:

>

Some imagined syntax?

dgList ~= (@capture i) {writeln(i + 2);};
// or:
dgList ~= (@capture i) => writeln(i + 2);

or,

"Fix this bug or I'll write this code."

string closure(string vars, string dg) {
    import std.string : split;

    string res = "{\n";
    foreach (var; vars.split(" ")) {
        res ~= "    auto " ~ var ~ " = " ~ var ~ ";\n";
    }
    res ~= "    return " ~ dg ~ ";\n}()";
    return res;
}

void main() {
    import std.stdio : writeln;

    void delegate()[] list;

    foreach (int i; [1, 2, 3]) {
        list ~= mixin(`i`.closure(`{ writeln(i); }`));
    }
    foreach (int i; [1, 2, 3]) {
        auto b = i + 2;
        list ~= mixin(/+ oops: +/`i`.closure(`{ writeln(b); }`));
    }

    foreach (dg; list)
        dg(); // output: 1 2 3 5 5 5
}

https://en.wikipedia.org/wiki/If_You_Don't_Buy_This_Book,_We'll_Kill_This_Dog!

September 29, 2021
On Wednesday, 29 September 2021 at 17:00:41 UTC, jfondren wrote:
> ```
> dgList ~= (i => { writeln(i + 2); })(i);
> ```
>
> is cleaner, but ISRT that this usage will be banned because people rarely intend what it actually means.

i => () => writeln(...)
« First   ‹ Prev
1 2 3 4