Value closures (no GC allocation)
Adam D. Ruppe via Digitalmars-d
digitalmars-d at puremagic.com
Sun May 21 11:17:57 PDT 2017
On Sunday, 21 May 2017 at 04:08:04 UTC, Vittorio Romeo wrote:
> This exact statement applied to C++ before C++11, but the
> introduction of lambda expression significantly changed the way
> people write and think about C++. Sometimes syntactic sugar can
> have huge impact on a language.
Oh absolutely, make no mistake, I would be FOR this addition. I
like it and do think it would be worth it in a lot of places.
But, using the struct stuff, we can add some artificial sweetener
now:
return bar(lambda!(x, q{ (int y) => x + y }));
You pass the captures first, then a q{} string literal of the
lambda. Here's the implementation of that lambda template:
template lambda(Args...) {
import std.conv;
import std.range;
import std.string;
string evil() {
// build the functor
import std.meta;
string code = "static struct anon {";
foreach(i; aliasSeqOf!(iota(0, Args.length-1)))
code ~= "typeof(Args[" ~ to!string(i) ~
"]) " ~ Args[i].stringof ~ ";";
string func = Args[$-1];
auto idx = func.indexOf("=>");
if(idx == -1)
throw new Exception("No => in lambda");
// or we could use one of the other styles
auto args = func[0 .. idx];
auto bod = func[idx + 2 .. $];
code ~= "auto opCall(T...)" ~ args ~ "{ return "
~ bod ~ "; }";
code ~= "this(T...)(T t) {
this.tupleof = t;
};";
code ~= "}";
return code;
}
mixin(evil());
anon lambda() {
anon a;
// copy the values in
a.tupleof = Args[0 .. $-1];
return a;
}
}
Yes, the C++ syntax is still a bit better and can give MUCH nicer
error messages, but for short things, this isn't bad.
> foreach(i; 0..5)
> {
> arr ~= () => writeln(i);
> }
so that's actually a long standing bug, but it hasn't been fixed
for a long time....
But to work with that, you can do a capture with a wrapper
function:
arr ~= ((i) => delegate() { writeln(i); })(i);
So you define a new function that returns the delegate and pass
the argument right there. This technique is common in Javascript.
Or, of course, using the artificial sweetener above, you can do:
arr ~= lambda!(i, q{ writeln(i); });
...assuming the imports are correct to call that library
function... so i'll grant the artificial sweetener can leave a
bitter aftertaste. (This is a good case to use in a feature
request as to why the string mixin trick isn't actually a great
replacement!)
More information about the Digitalmars-d
mailing list