We need to have a way to say "convert this nested function into a struct"
John Colvin via Digitalmars-d
digitalmars-d at puremagic.com
Wed Oct 28 04:42:06 PDT 2015
On Saturday, 6 June 2015 at 12:49:37 UTC, Atila Neves wrote:
> On Saturday, 6 June 2015 at 06:59:26 UTC, Jonathan M Davis
> wrote:
>> On Saturday, 6 June 2015 at 06:16:17 UTC, Andrei Alexandrescu
>> wrote:
>>> Nested functions that allocate their environment dynamically
>>> can be quite useful. However, oftentimes the need is to
>>> convert the code plus the data needed into an anonymous
>>> struct that copies the state inside, similar to C++ lambdas
>>> that capture by value.
>>>
>>> I wonder how to integrate that within the language nicely.
>>
>> Some of us were discussing this at dconf. Essentially, we need
>> a way to create a functor similar to how C++ lambdas do. The
>> most straightforward way would involve string mixins, and
>> you'd do something like
>>
>> auto f = makeFunctor!"function code here"(arguments);
>> auto result = range.algorithm!f();
>>
>> but that's not terribly pretty. Atila seemed to have figured
>> out how we could do it with std.functional.partial, but I was
>> too tired at the time to quite understand what his proposal
>> was. So, we may have something better there. Ideally, we'd be
>> able to just give a lambda, but that would put us right back
>> in the problem of a delegate being allocated unnecessarily
>> (though IIRC, Atila's suggestion somehow worked with lambdas
>> and partial without allocating; I wish that I could remember
>> what he proposed). But while it may or not be as pretty as
>> we'd like, I think that it's at last _possible_ for us to have
>> a shorthand for creating a functor by just providing the
>> function's body and arguments that hold the values for its
>> members. I'm certainly not against finding a language way to
>> make it prettier though, since I'm not sure how clean we can
>> really do it without language help.
>>
>> That being said, we really should find a way to make it so
>> that lambda's don't turn into delegates unless they really
>> need to. In many, many cases, they should be plenty efficient
>> without having to force the issue with functors, but they
>> aren't, because we allocate for them unnecessarily. I don't
>> know how easy it'll be though for the compiler devs to figure
>> out how to optimize that, since sometimes you _do_ need to
>> allocate a closure.
>>
>> But having a shorthand way to create functors would definitely
>> allow us to force the issue where necessary. And from what
>> Liran was saying at dconf, that alone would make it possible
>> for them to use a lot of Phobos that they can't right now. I
>> suspect that unnecessary closures are actually the main reason
>> that we have GC allocation problems with Phobos, since most
>> algorithms just don't explicitly involve allocation unless
>> they're doing array-specific stuff.
>>
>> - Jonathan M Davis
>
> I remember the conversation but not really what I said.
> However, I just wrote this:
>
>
> import std.stdio;
> import std.algorithm;
> import std.range;
> import std.conv;
> import std.traits;
> import std.exception;
>
>
> auto functorPartial(alias F, T)(T arg) {
> struct Functor {
>
> T arg;
>
> this(T args) { //because of opCall
> this.arg = arg;
> }
>
> auto opCall(U...)(U rest) {
> return F(arg, rest);
> }
> }
>
> return Functor(arg);
> }
>
> int adder(int i, int j) {
> return i + j;
> }
>
> void main(string[] args) {
>
> enforce(args.length > 1, "An argument must be passed in");
>
> auto arg = args[1].to!int; //to prove it's at runtime
> auto adderPartial = functorPartial!adder(arg); //runtime
> value
> writeln("adder result: ", adderPartial(4));
>
> //"subtracter"? "subtractor"? who cares
> auto subtracterPartial = functorPartial!((a, b) => a -
> b)(arg);
> writeln("subtracter partial: ", subtracterPartial(4));
>
> }
Unfortunately this doesn't solve the problem in general with
@nogc. When passing one of these functors to e.g.
std.algorithm.map, there is no way to avoid the reference to the
current scope. The challenge is to implement a (correct, see
https://issues.dlang.org/show_bug.cgi?id=14982) @nogc version of
this function without rewriting map:
auto foo(int a)
{
return iota(10).map!(x => x + a);
}
I don't think it can be done without language changes.
I wonder what could be done if we could get inspect and
manipulate context pointers in code...
More information about the Digitalmars-d
mailing list