Thread overview | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 05, 2017 lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
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. |
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon Bürger | 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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stefan Koch | 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:
>> 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.
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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon Bürger | 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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Stefan Koch | 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:
>> 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.
>
> 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.
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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon Bürger | 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:
>> [...]
>
> 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.
Maybe std.functional.partial can help you.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to ikod | 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:
>> On Saturday, 5 August 2017 at 18:22:38 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.
>
> Maybe std.functional.partial can help you.
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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to ikod | 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.
|
August 05, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simon Bürger | 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:
>> 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.
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());
|
August 06, 2017 Re: lambda function with "capture by value" | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johnson Jones | 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.
|
Copyright © 1999-2021 by the D Language Foundation