Thread overview | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 16, 2015 How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cym13 | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to cym13 | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to FreeSlave | 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 Re: How to provide this arg or functor for algorithm? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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?
|
Copyright © 1999-2021 by the D Language Foundation