| 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
Permalink
Reply