Jump to page: 1 2
Thread overview
templatized delegate
May 22, 2017
Alex
May 22, 2017
Dukc
May 22, 2017
Alex
May 22, 2017
ag0aep6g
May 22, 2017
Alex
May 23, 2017
Alex
May 23, 2017
Nicholas Wilson
May 23, 2017
Stanislav Blinov
May 23, 2017
Alex
May 23, 2017
Stanislav Blinov
May 23, 2017
Alex
May 23, 2017
Alex
May 23, 2017
ag0aep6g
May 23, 2017
Alex
May 23, 2017
9il
May 22, 2017
Hi, all
I have a question, how to handle a templated delegate. However, I'm not sure, if I'm going in the right direction, so I have three examples, and my question is about the third.

1. Here, a struct with an alias is defined and on its creation the delegate get known to the struct. Everything is ok.

struct A(alias dg)
{
	auto fun(int i, string s)
	{
		return dg(i, s);
	}
}

void main()
{
	
	auto dlg(int i, string s)
	{
		import std.stdio;
		writeln(i, " ", s);
	}
	auto a = A!dlg();
	a.fun(5, "a");
}

2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B.

struct A(alias dg)
{
	auto fun(int i, string s)
	{
		return dg(i, s);
	}
}

struct B
{
	A!dlgptr a;
	static void delegate(int, string) dlgptr; // here, without the "static" "need 'this' to access member dlgptr" rises
	this(void delegate(int, string) dlg)
	{
		dlgptr = dlg;
	}
	void fun(int i, string s)
	{
		a.fun(i, s);
	}
}

void main()
{
	auto dlg(int i, string s)
	{
		import std.stdio;
		writeln(i, " ", s);
	}
	auto b = B(&dlg);
	b.fun(5, "a");
}

3. Now the hard stuff comes. I want to templatize my delegate.
struct A(alias dg)
{
	auto fun(T, U...)(T t, U u)
	{
		return dg!(T, U)(t, u);
	}
}

struct C
{
	A!dlgptr a;
	
	/* static? */ template dlgptr(T, U...)
	{
		/* static? */ void delegate(T, U) dlgptr;
	}

	this(???)
	{
		???
	}
	
	void fun(T, U...)(T t, U args)
	{
		dlgptr!(T, U)(t, args);
	}
}

void main()
{
	auto dlg(T, U...)(T t, U u)
	{
		import std.stdio;
		writeln(t, " ", u);
	}
	
	auto c = C(???);
	c.fun(5, "a"); // exception, obviously, as C is not initialized properly
	
	A!dlg a;
	a.fun(5, "a"); //Error: function test92.A!(dlg).A.fun!(int, string).fun cannot get frame pointer to test92.main.dlg!(int, string).dlg
}

Here, nothing works any more... I have no idea, what to pass to the struct C, as a template is not an lvalue. But even the direct initialization of A doesn't work...

By the way, I found
http://forum.dlang.org/post/xiycyjndqzbohjtjfjvh@forum.dlang.org
and
http://www.digitalmars.com/d/archives/digitalmars/D/learn/delegate_template_and_alias_31092.html
these both go into the right direction I think... but don't see, how to reformulate them...
Thanks in advance :)
May 22, 2017
On Monday, 22 May 2017 at 09:04:15 UTC, Alex wrote:
> 2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B.

The reason it does not work with a non-static member is that A generated has no way of knowing where B that contains the delegate to be called resides. But it works when done this way:

struct A(alias dg)
{
    auto fun(T...)(T params)
    {
        return dg(params);
    }
}

struct B
{
    A!((B b, int i, string a) => b.dlgptr(i, a)) a;
    void delegate(int, string) dlgptr;
    this(void delegate(int, string) dlg)
    {
        dlgptr = dlg;
    }
    void fun(int i, string s)
    {
        a.fun(this, i, s);
    }
}

void main()
{
    auto dlg(int i, string s)
    {
        import std.stdio;
        writeln(i, " ", s);
    }
    auto b = B(&dlg);
    b.fun(5, "a");
}

I wasn't in mood to look at C though, so I don't know if this helps.
May 22, 2017
On Monday, 22 May 2017 at 20:38:27 UTC, Dukc wrote:
> On Monday, 22 May 2017 at 09:04:15 UTC, Alex wrote:
>> 2. Now, I want to store the delegate in another struct. If I want to do this, I have to define the pointer as static. This is not intended at the beginning, but it's ok, as I know, that the delegate would be the same across all instances of B.
>
> The reason it does not work with a non-static member is that A generated has no way of knowing where B that contains the delegate to be called resides. But it works when done this way:
>
> struct A(alias dg)
> {
>     auto fun(T...)(T params)
>     {
>         return dg(params);
>     }
> }
>
> struct B
> {
>     A!((B b, int i, string a) => b.dlgptr(i, a)) a;
>     void delegate(int, string) dlgptr;
>     this(void delegate(int, string) dlg)
>     {
>         dlgptr = dlg;
>     }
>     void fun(int i, string s)
>     {
>         a.fun(this, i, s);
>     }
> }
>
> void main()
> {
>     auto dlg(int i, string s)
>     {
>         import std.stdio;
>         writeln(i, " ", s);
>     }
>     auto b = B(&dlg);
>     b.fun(5, "a");
> }
>
> I wasn't in mood to look at C though, so I don't know if this helps.

Yes, it does :)
The step to the C variant is, how to rewrite the lines

A!((B b, int i, string a) => b.dlgptr(i, a)) a;
and
this(void delegate(int, string) dlg)

if I want to define my delegate as a template:

template dlgptr(T, U...)
{
    void delegate(T, U) dlgptr;
}
May 22, 2017
On 05/22/2017 11:04 AM, Alex wrote:
> 3. Now the hard stuff comes. I want to templatize my delegate.
> struct A(alias dg)
> {
>      auto fun(T, U...)(T t, U u)
>      {
>          return dg!(T, U)(t, u);
>      }
> }
> 
> struct C
> {
>      A!dlgptr a;
> 
>      /* static? */ template dlgptr(T, U...)
>      {
>          /* static? */ void delegate(T, U) dlgptr;
>      }
> 
>      this(???)
>      {
>          ???
>      }
> 
>      void fun(T, U...)(T t, U args)
>      {
>          dlgptr!(T, U)(t, args);
>      }
> }
> 
> void main()
> {
>      auto dlg(T, U...)(T t, U u)
>      {
>          import std.stdio;
>          writeln(t, " ", u);
>      }
> 
>      auto c = C(???);
>      c.fun(5, "a"); // exception, obviously, as C is not initialized properly
> 
>      A!dlg a;
>      a.fun(5, "a"); //Error: function test92.A!(dlg).A.fun!(int, string).fun cannot get frame pointer to test92.main.dlg!(int, string).dlg
> }
> 
> Here, nothing works any more... I have no idea, what to pass to the struct C, as a template is not an lvalue.

Not only is a template not an lvalue, it's not any kind of value at all. It doesn't have a type. You can't have a variable holding a template. You can't pass it as an argument.

But a template is a symbol. You can pass it in an alias parameter. So to pass dlg to C, you have to make C a template with an alias parameter, like A is.

> But even the direct initialization of A doesn't work...
`A!dlg a;` works. Calling `fun` doesn't.

A.fun instantiates dlg, resulting in a delegate that should be able to access main's stuff. But it's not guaranteed that main is active when A.fun is called. You could have returned `a` from main before calling fun. For an actual delegate, a closure would be made in that case. But dlg isn't a delegate, it's a template. I guess it's not possible (or not feasible, or not implemented) to create a closure a template like this.

If you don't actually need dlg to access main's stuff, you can make it static. It's a function then and the delegate weirdness doesn't apply.

For another approach to your problem, maybe have a look at run-time variadic arguments:

https://dlang.org/spec/function.html#d_style_variadic_functions

With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
May 22, 2017
On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
> On 05/22/2017 11:04 AM, Alex wrote:
>> [...]
>
> Not only is a template not an lvalue, it's not any kind of value at all. It doesn't have a type. You can't have a variable holding a template. You can't pass it as an argument.
>
> But a template is a symbol. You can pass it in an alias parameter. So to pass dlg to C, you have to make C a template with an alias parameter, like A is.

Aha... ok, I see...

>
>> [...]
> `A!dlg a;` works. Calling `fun` doesn't.
>
> A.fun instantiates dlg, resulting in a delegate that should be able to access main's stuff. But it's not guaranteed that main is active when A.fun is called. You could have returned `a` from main before calling fun. For an actual delegate, a closure would be made in that case. But dlg isn't a delegate, it's a template. I guess it's not possible (or not feasible, or not implemented) to create a closure a template like this.

ok, I see the point, I think...

>
> If you don't actually need dlg to access main's stuff, you can make it static. It's a function then and the delegate weirdness doesn't apply.
>

yeah... no :)
the function inside the main has to have access to the main stuff. Its the pointer inside C which could be static, if this would help. So long, I go for the enhanced second variant...

> For another approach to your problem, maybe have a look at run-time variadic arguments:
>
> https://dlang.org/spec/function.html#d_style_variadic_functions
>
> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.

Hm... You are probably right... and variadic functions do not really match the idea...
May 23, 2017
On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.

By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function:

import std.stdio;
import mir.random;

void main()
{
	Random rndGen = Random(unpredictableSeed);
	fun(rndGen);
}

void fun(...)
{

}

Yields "... is not copyable because it is annotated with @disable" :)
May 23, 2017
On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:
> On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
>> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
>
> By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function:
>
> import std.stdio;
> import mir.random;
>
> void main()
> {
> 	Random rndGen = Random(unpredictableSeed);
> 	fun(rndGen);
> }
>
> void fun(...)
> {
>
> }
>
> Yields "... is not copyable because it is annotated with @disable" :)

Random is copy @disabled to prevent incorrect use.
You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address.
fun(&rndGen);
May 23, 2017
On Tuesday, 23 May 2017 at 10:42:54 UTC, Nicholas Wilson wrote:
> On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:
>> On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
>>> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
>>
>> By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function:
>>
>> import std.stdio;
>> import mir.random;
>>
>> void main()
>> {
>> 	Random rndGen = Random(unpredictableSeed);
>> 	fun(rndGen);
>> }
>>
>> void fun(...)
>> {
>>
>> }
>>
>> Yields "... is not copyable because it is annotated with @disable" :)
>
> Random is copy @disabled to prevent incorrect use.
> You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address.
> fun(&rndGen);

void variadic(Args...)(auto ref Args args) { /* ... */ }

This infers whether you pass lvalues or rvalues. If passing further down the chain of such calls is needed, one can use std.functional : fowrard :

void variadic(Args...)(auto ref Args args) {
    import std.functional : forward;
    doStuff(forward!args);
}

void doStuff(Args...)(auto ref Args args) {
    /* ... */
}

'forward' aliases ref arguments (i.e. passed lvalues) and moves value arguments (i.e. passed rvalues).

If a value is not copyable, it may be move-able (check the docs though, it may not be that either).

void fun(Args...)(auto ref Args args) { /*...*/ }

import std.algorithm : move;

auto a = NonCopyable(42);

fun(move(a));
// or:
func(NonCopyable(42));
May 23, 2017
On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:
> On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
>> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
>
> By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function:
>
> import std.stdio;
> import mir.random;
>
> void main()
> {
> 	Random rndGen = Random(unpredictableSeed);
> 	fun(rndGen);
> }
>
> void fun(...)
> {
>
> }
>
> Yields "... is not copyable because it is annotated with @disable" :)

1. Pass its pointer
2. Use variadic template with auto ref:

```
void foo(T...)(auto ref T tup)
{
}
```

May 23, 2017
On Tuesday, 23 May 2017 at 10:42:54 UTC, Nicholas Wilson wrote:
> On Tuesday, 23 May 2017 at 10:30:56 UTC, Alex wrote:
>> On Monday, 22 May 2017 at 21:44:17 UTC, ag0aep6g wrote:
>>> With that kind of variadics, you're not dealing with a template. A (run-time) variadic delegate is an actual delegate, i.e. a value that can be passed around. But the variadic stuff is a bit weird to use, and probably affects performance.
>>
>> By the way, I'm not even sure, if variadics work in my case. I have a strange struct of a random generator, which cannot be copied, and I have no idea how to pass it to a variadic function:
>>
>> import std.stdio;
>> import mir.random;
>>
>> void main()
>> {
>> 	Random rndGen = Random(unpredictableSeed);
>> 	fun(rndGen);
>> }
>>
>> void fun(...)
>> {
>>
>> }
>>
>> Yields "... is not copyable because it is annotated with @disable" :)
>
> Random is copy @disabled to prevent incorrect use.

Yes, I'm aware of this...

> You need to pass it by ref or pointer. I dont know if you can pass variables as ref to a variadic, but you should be able to pass it by address.
> fun(&rndGen);

No, you can't pass a ref into a variadic... if the test above is written correct.
And no, I can't pass it by adress, as I don't know apriori, whether the very parameter which gets the random generator is already a part of the variadic parameters, or a well defined ref parameter.
Especially, there are some functions for both cases. While the argument list remains the same, the acceptor part is meant to work with it somehow.
The other way around would be, to manipulate the argument list, which is shared...
« First   ‹ Prev
1 2