Jump to page: 1 2
Thread overview
How to provide this arg or functor for algorithm?
Aug 16, 2015
FreeSlave
Aug 16, 2015
cym13
Aug 16, 2015
Adam D. Ruppe
Aug 16, 2015
cym13
Aug 16, 2015
FreeSlave
Aug 16, 2015
Ali Çehreli
Aug 16, 2015
FreeSlave
Aug 16, 2015
FreeSlave
Aug 16, 2015
Ali Çehreli
Aug 16, 2015
cym13
Aug 16, 2015
Ali Çehreli
Aug 17, 2015
anonymous
Aug 17, 2015
thedeemon
Aug 17, 2015
anonymous
Aug 17, 2015
thedeemon
Aug 17, 2015
thedeemon
Aug 17, 2015
anonymous
August 16, 2015
Let's say I want to map some range using some context.
The obvious way is to do:

uint[3] arr = [1,2,3];
uint context = 2;
auto r = arr[].map!(delegate(value) { return value * context; });

The problem is that this allocates delegate, so it can't be used in @nogc code.
What I want to do might look like this:

static struct Caller
{
    this(uint context) @nogc {
        _context = context;
    }
    auto opCall(uint value) @nogc {
        return value * _context;
    }
    uint _context;
}

auto caller = Caller(2);
auto r = arr[].map!(&caller.opCall);

But it will not work of course since function must be a compile-time parameter.

So the way to go would be:

auto caller = Caller(2);
auto r = arr[].map!(Caller.opCall)(&caller);

But map and other algorithms don't support this interface.

The other way is

auto r = arr.map!(Caller(2));

But again, since it's template parameter, it can't use variables unknown at compile time:

uint context = ...;
auto r = arr.map!(Caller(context)); //will not work

So what's the solution? Of course besides rewriting the whole std.algorithm.
August 16, 2015
On Sunday, 16 August 2015 at 11:53:42 UTC, FreeSlave wrote:
> Let's say I want to map some range using some context.
> The obvious way is to do:
>
> uint[3] arr = [1,2,3];
> uint context = 2;
> auto r = arr[].map!(delegate(value) { return value * context; });

To me the obvious way is to use a lambda, not a delegate:

    uint[3] arr = [1,2,3];
    uint context = 2;
    auto r = arr[].map!(value => value * context);
August 16, 2015
On Sunday, 16 August 2015 at 12:04:51 UTC, cym13 wrote:
> To me the obvious way is to use a lambda, not a delegate:

Lambdas and delegates are the same thing, just different syntax.

August 16, 2015
On Sunday, 16 August 2015 at 11:53:42 UTC, FreeSlave wrote:
> Let's say I want to map some range using some context.
> The obvious way is to do:
>
> uint[3] arr = [1,2,3];
> uint context = 2;
> auto r = arr[].map!(delegate(value) { return value * context; });
>
> The problem is that this allocates delegate, so it can't be used in @nogc code.
> What I want to do might look like this:
>
> static struct Caller
> {
>     this(uint context) @nogc {
>         _context = context;
>     }
>     auto opCall(uint value) @nogc {
>         return value * _context;
>     }
>     uint _context;
> }
>
> auto caller = Caller(2);
> auto r = arr[].map!(&caller.opCall);
>
> But it will not work of course since function must be a compile-time parameter.
>
> So the way to go would be:
>
> auto caller = Caller(2);
> auto r = arr[].map!(Caller.opCall)(&caller);
>
> But map and other algorithms don't support this interface.
>
> The other way is
>
> auto r = arr.map!(Caller(2));
>
> But again, since it's template parameter, it can't use variables unknown at compile time:
>
> uint context = ...;
> auto r = arr.map!(Caller(context)); //will not work
>
> So what's the solution? Of course besides rewriting the whole std.algorithm.

Ok, so as my lambda proposition obviously doesn't work, here is one way that does using a templated function. There may be a way to make it shorter, I don't know.


    import std.conv;
    import std.stdio;

    template fun(uint context) {
        static uint withContext(uint value) {
            return value * context;
        }

        auto fun(uint[] arr) @nogc {
            return arr.map!withContext;
        }
    }

    void main(string[] args) {
        [1, 2, 3].to!(uint[])
                 .fun!2
                 .writeln;
    }

August 16, 2015
On Sunday, 16 August 2015 at 12:30:54 UTC, cym13 wrote:
> On Sunday, 16 August 2015 at 11:53:42 UTC, FreeSlave wrote:
>> [...]
>
> Ok, so as my lambda proposition obviously doesn't work, here is one way that does using a templated function. There may be a way to make it shorter, I don't know.
>
>
>     import std.conv;
>     import std.stdio;
>
>     template fun(uint context) {
>         static uint withContext(uint value) {
>             return value * context;
>         }
>
>         auto fun(uint[] arr) @nogc {
>             return arr.map!withContext;
>         }
>     }
>
>     void main(string[] args) {
>         [1, 2, 3].to!(uint[])
>                  .fun!2
>                  .writeln;
>     }

It works only because 2 is known constant at compile time.
August 16, 2015
On 08/16/2015 04:53 AM, FreeSlave wrote:

> The problem is that this allocates delegate, so it can't be used in
> @nogc code.

Would constructing the delegate by setting its .funcptr and .ptr properties work in this case? You can have a pool of context objects which become the context for the delegate.

  http://ddili.org/ders/d.en/lambda.html#ix_lambda..funcptr

Ali

August 16, 2015
On Sunday, 16 August 2015 at 15:29:10 UTC, Ali Çehreli wrote:
> On 08/16/2015 04:53 AM, FreeSlave wrote:
>
> > The problem is that this allocates delegate, so it can't be
> used in
> > @nogc code.
>
> Would constructing the delegate by setting its .funcptr and .ptr properties work in this case? You can have a pool of context objects which become the context for the delegate.
>
>   http://ddili.org/ders/d.en/lambda.html#ix_lambda..funcptr
>
> Ali

I don't see how this can solve the problem.

What I tried:

import std.stdio;
import std.range;
import std.algorithm;

struct Caller
{
    this(uint context) {
        _context = context;
    }
    uint method(uint value) {
        return _context * value;
    }

    uint _context;
}

@nogc auto func(uint[] arr, uint function(uint) f)
{
    return arr.map!(f);
}

void main(string[] args)
{
    uint[] arr = [1,2,3];
    uint context = 2;
    auto c = Caller(context);
    auto d = &c.method;
    writeln(func(arr, d.funcptr));
}

It still says it needs allocation:

test.d(17): Error: function test.func @nogc function allocates a closure with the GC

funcptr does not play any role here, since passing the delegate directly leads to the same error.

August 16, 2015
On Sunday, 16 August 2015 at 16:23:05 UTC, FreeSlave wrote:
> On Sunday, 16 August 2015 at 15:29:10 UTC, Ali Çehreli wrote:
>> On 08/16/2015 04:53 AM, FreeSlave wrote:
>>
>> > The problem is that this allocates delegate, so it can't be
>> used in
>> > @nogc code.
>>
>> Would constructing the delegate by setting its .funcptr and .ptr properties work in this case? You can have a pool of context objects which become the context for the delegate.
>>
>>   http://ddili.org/ders/d.en/lambda.html#ix_lambda..funcptr
>>
>> Ali
>
> I don't see how this can solve the problem.
>
> What I tried:
>
> import std.stdio;
> import std.range;
> import std.algorithm;
>
> struct Caller
> {
>     this(uint context) {
>         _context = context;
>     }
>     uint method(uint value) {
>         return _context * value;
>     }
>
>     uint _context;
> }
>
> @nogc auto func(uint[] arr, uint function(uint) f)
> {
>     return arr.map!(f);
> }
>
> void main(string[] args)
> {
>     uint[] arr = [1,2,3];
>     uint context = 2;
>     auto c = Caller(context);
>     auto d = &c.method;
>     writeln(func(arr, d.funcptr));
> }
>
> It still says it needs allocation:
>
> test.d(17): Error: function test.func @nogc function allocates a closure with the GC
>
> funcptr does not play any role here, since passing the delegate directly leads to the same error.

Forgot about data ptr.

@nogc auto func(uint[] arr, uint function(uint) f, void* data)
{
    uint delegate(uint) d;
    d.funcptr = f;
    d.ptr = data;
    return arr.map!(d);
}

void main(string[] args)
{
    uint[] arr = [1,2,3];
    uint context = 2;
    auto c = Caller(context);
    auto d = &c.method;
    writeln(func(arr, d.funcptr, d.ptr));
}

Still the same error though.
August 16, 2015
On 08/16/2015 09:26 AM, FreeSlave wrote:

>> It still says it needs allocation:
>>
>> test.d(17): Error: function test.func @nogc function allocates a
>> closure with the GC

I wrapped it inside a class object but it still thinks it needs to allocate:

import std.stdio;
import std.range;
import std.algorithm;

struct Caller
{
    this(uint context) {
        _context = context;
    }
    uint method(uint value) {
        return _context * value;
    }

    uint _context;
}

class DelegateRef
{
    uint delegate(uint) d;

    this (uint delegate(uint) d)
    {
        this.d = d;
    }
}

// HERE:
// Error: function deneme.func @nogc function allocates
//        a closure with the GC
@nogc auto func(uint[] arr, DelegateRef d)
{
    return arr.map!(a => d.d(a));
}

void main(string[] args)
{
    uint[] arr = [1,2,3];
    uint context = 2;
    auto c = Caller(context);
    auto d = &c.method;

    writeln(func(arr, new DelegateRef(d)));
}

Ali

August 16, 2015
On Sunday, 16 August 2015 at 22:22:07 UTC, Ali Çehreli wrote:
>
> // HERE:
> // Error: function deneme.func @nogc function allocates
> //        a closure with the GC
> @nogc auto func(uint[] arr, DelegateRef d)
> {
>     return arr.map!(a => d.d(a));
> }

Aren't you making another delegate in the map by using "=>" that needs to allocate because it uses 'd' which is out of its scope?
« First   ‹ Prev
1 2