digitalmars.D.learn - lambda function with "capture by value"
- Simon =?UTF-8?B?QsO8cmdlcg==?= (14/14) Aug 05 2017 If a lambda function uses a local variable, that variable is
- Stefan Koch (2/16) Aug 05 2017 No currently there is not.
- Stefan Koch (5/24) Aug 05 2017 and it'd be rather useless I guess.
- Simon =?UTF-8?B?QsO8cmdlcg==?= (16/41) Aug 05 2017 No, sometimes I want i to be the value it has at the time the
- ikod (2/19) Aug 05 2017 Maybe std.functional.partial can help you.
- Simon =?UTF-8?B?QsO8cmdlcg==?= (7/32) Aug 05 2017 Thanks. But std.functional.partial takes the fixed arguments as
- Simon =?UTF-8?B?QsO8cmdlcg==?= (13/14) Aug 05 2017 Nope.
- Temtaime (8/22) Aug 05 2017 This one works
- Adam D. Ruppe (13/14) Aug 06 2017 Yeah, that's how I'd do it - make a function taking arguments by
- Russel Winder via Digitalmars-d-learn (15/24) Aug 06 2017 Assuming I have understood the problem, this is the solution necessary i...
- Simon =?UTF-8?B?QsO8cmdlcg==?= (5/19) Aug 06 2017 I like the (kinda cryptic IMO) look of this '(k){...}(i)'
- Johnson Jones (20/34) Aug 05 2017 There is, but it isn't pretty.
- Adam D. Ruppe (3/5) Aug 06 2017 It actually does it at function entry, allocating the memory for
- bitwise (15/29) Aug 06 2017 I asked about this a couple of day ago:
If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.
Aug 05 2017
On Saturday, 5 August 2017 at 18:17:49 UTC, Simon Bürger wrote:If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.No currently there is not.
Aug 05 2017
On Saturday, 5 August 2017 at 18:19:05 UTC, Stefan Koch wrote:On Saturday, 5 August 2017 at 18:17:49 UTC, Simon Bürger wrote:and it'd be rather useless I guess. You want i to be whatever the context i is a the point where you call the delegate. Not at the point where you define the delegate.If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.No currently there is not.
Aug 05 2017
On Saturday, 5 August 2017 at 18:22:38 UTC, Stefan Koch wrote:On Saturday, 5 August 2017 at 18:19:05 UTC, Stefan Koch wrote:No, sometimes I want i to be the value it has at the time the delegate was defined. My actual usecase was more like this: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) dgs[i] = (){writefln("%s", i); }; And I want three different delegates, not three times the same. I tried the following: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) { int j = i; dgs[i] = (){writefln("%s", j); }; } I thought that 'j' should be considered a new variable each time around, but sadly it doesn't work.On Saturday, 5 August 2017 at 18:17:49 UTC, Simon Bürger wrote:and it'd be rather useless I guess. You want i to be whatever the context i is a the point where you call the delegate. Not at the point where you define the delegate.If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.No currently there is not.
Aug 05 2017
On Saturday, 5 August 2017 at 18:45:34 UTC, Simon Bürger wrote:On Saturday, 5 August 2017 at 18:22:38 UTC, Stefan Koch wrote:Maybe std.functional.partial can help you.[...]No, sometimes I want i to be the value it has at the time the delegate was defined. My actual usecase was more like this: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) dgs[i] = (){writefln("%s", i); }; And I want three different delegates, not three times the same. I tried the following: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) { int j = i; dgs[i] = (){writefln("%s", j); }; } I thought that 'j' should be considered a new variable each time around, but sadly it doesn't work.
Aug 05 2017
On Saturday, 5 August 2017 at 18:54:22 UTC, ikod wrote:On Saturday, 5 August 2017 at 18:45:34 UTC, Simon Bürger wrote:Thanks. But std.functional.partial takes the fixed arguments as template parameters, so they must be known at compile-time. Anyway, I solved my problem already a while ago by replacing delegates with custom structures which overload the call-operator. I opened this thread just out of curiosity. Takes a couple lines more but works fine.On Saturday, 5 August 2017 at 18:22:38 UTC, Stefan Koch wrote:Maybe std.functional.partial can help you.[...]No, sometimes I want i to be the value it has at the time the delegate was defined. My actual usecase was more like this: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) dgs[i] = (){writefln("%s", i); }; And I want three different delegates, not three times the same. I tried the following: void delegate()[3] dgs; for(int i = 0; i < 3; ++i) { int j = i; dgs[i] = (){writefln("%s", j); }; } I thought that 'j' should be considered a new variable each time around, but sadly it doesn't work.
Aug 05 2017
On Saturday, 5 August 2017 at 18:54:22 UTC, ikod wrote:Maybe std.functional.partial can help you.Nope. int i = 1; alias dg = partial!(writeln, i); i = 2; dg(); still prints '2' as it should because 'partial' takes 'i' as a symbol, which is - for this purpose - kinda like "by reference". Anyway, I solved my problem already a while ago by replacing delegates with custom struct's that implement the call-operator. I started this thread just out of curiosity, because as I see it, the purpose of lambdas is pretty much to remove the need for such custom constructions.
Aug 05 2017
On Saturday, 5 August 2017 at 19:19:06 UTC, Simon Bürger wrote:On Saturday, 5 August 2017 at 18:54:22 UTC, ikod wrote:This one works void delegate()[3] dgs; for(int i = 0; i < 3; ++i) { (k){ dgs[k] = {writefln("%s", k); }; }(i); } dgs.each!(a => a());Maybe std.functional.partial can help you.Nope. int i = 1; alias dg = partial!(writeln, i); i = 2; dg(); still prints '2' as it should because 'partial' takes 'i' as a symbol, which is - for this purpose - kinda like "by reference". Anyway, I solved my problem already a while ago by replacing delegates with custom struct's that implement the call-operator. I started this thread just out of curiosity, because as I see it, the purpose of lambdas is pretty much to remove the need for such custom constructions.
Aug 05 2017
On Saturday, 5 August 2017 at 19:58:08 UTC, Temtaime wrote:(k){ dgs[k] = {writefln("%s", k); }; }(i);Yeah, that's how I'd do it - make a function taking arguments by value that return the delegate you actually want to store. (Also use this pattern in Javascript btw for its `var`, though JS now has `let` which works without this trick... and D is supposed to work like JS `let` it is just buggy). You could also define a struct with members for the values you want, populate it, and pass one of its methods as your delegate. It is syntactically the heaviest but does give the most precise control (and you can pass the struct itself by value to avoid the memory allocation entirely if you want). But for the loop, the pattern Temtaime wrote is how I'd prolly do it.
Aug 06 2017
On Sun, 2017-08-06 at 12:50 +0000, Adam D. Ruppe via Digitalmars-d-learn wrote:On Saturday, 5 August 2017 at 19:58:08 UTC, Temtaime wrote:Assuming I have understood the problem, this is the solution necessary in Python: you have to use an enclosing function around the function so as to capture the value using a parameter. I think Java requires the same. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder=C2=A0 (k){ dgs[k] =3D {writefln("%s", k); }; }(i);=20 Yeah, that's how I'd do it - make a function taking arguments by=C2=A0 value that return the delegate you actually want to store. (Also=C2=A0 use this pattern in Javascript btw for its `var`, though JS now=C2=A0 has `let` which works without this trick... and D is supposed to=C2=A0 work like JS `let` it is just buggy). =20
Aug 06 2017
On Sunday, 6 August 2017 at 12:50:22 UTC, Adam D. Ruppe wrote:On Saturday, 5 August 2017 at 19:58:08 UTC, Temtaime wrote:I like the (kinda cryptic IMO) look of this '(k){...}(i)' construction. But for my actual code I went with struct+opCall without any delegate at all. Anyway, thanks for all your suggestions.(k){ dgs[k] = {writefln("%s", k); }; }(i);Yeah, that's how I'd do it - make a function taking arguments by value that return the delegate you actually want to store. (Also use this pattern in Javascript btw for its `var`, though JS now has `let` which works without this trick... and D is supposed to work like JS `let` it is just buggy). You could also define a struct with members for the values you want, populate it, and pass one of its methods as your delegate. It is syntactically the heaviest but does give the most precise control (and you can pass the struct itself by value to avoid the memory allocation entirely if you want). But for the loop, the pattern Temtaime wrote is how I'd prolly do it.
Aug 06 2017
On Saturday, 5 August 2017 at 18:17:49 UTC, Simon Bürger wrote:If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.There is, but it isn't pretty. import std.stdio; void main() { int i = 1; int* n = null; auto dg = (){ if (n is null) n = cast(int*)i; else writefln("%s", n); }; dg(); i = 2; dg(); // prints '1' } 1. I'm pretty sure that D creates the delegate "lazily" in the sense that the first call is what captures the variable. Hence, we must call it where we want to capture, not after the change occurs. 2. We use a temp local variable to act as a place holder. A singleton basically. You might be able to wrap this up in some type of template that makes it easier to use but it does work.
Aug 05 2017
On Saturday, 5 August 2017 at 18:37:31 UTC, Johnson Jones wrote:1. I'm pretty sure that D creates the delegate "lazily" in the sense that the first call is what captures the variable.It actually does it at function entry, allocating the memory for the locals in the closure, so it never actually copies them.
Aug 06 2017
On Saturday, 5 August 2017 at 18:17:49 UTC, Simon Bürger wrote:If a lambda function uses a local variable, that variable is captured using a hidden this-pointer. But this capturing is always by reference. Example: int i = 1; auto dg = (){ writefln("%s", i); }; i = 2; dg(); // prints '2' Is there a way to make the delegate "capture by value" so that the call prints '1'? Note that in C++, both variants are available using [&]() { printf("%d", i); } and [=]() { printf("%d", i); } respectively.I asked about this a couple of day ago: http://forum.dlang.org/thread/ckkswkkvhfojbcczijim forum.dlang.org The problem is that the lambda captures the entire enclosing stack frame. This is actually a bug because the lambda should only capture the enclosing *scope*, not the entire stack frame of the function. So even if you were to copy `i` into a temporary in for example), that temporary would still reside in the same stack frame as the outer `i`, which means there would still be only one copy of it. There is a workaround in Timon's post here: http://forum.dlang.org/post/om2aqp$2e9t$1 digitalmars.com Basically, that workaround wraps the nested scope in another lambda to force the creation of a separate stack frame.
Aug 06 2017