www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to pass a member function/delegate into a mixin template?

reply =?UTF-8?B?IuWyqeWAiSDmvqoi?= <mio.iwakura gmail.com> writes:
Hi all,

I've been reading D Cookbook, in which the author recommends the 
use of mixin templates to essentially hold boilerplate code for 
classes (page 28). Referencing TDPL reaffirms this strategy. With 
this design choice in mind, I would like to be able to use a 
mixin template that creates a slot for me (as in signals & slots) 
and provides a constructor that connects it to the signal.

The closest I have come is in the simplified example given below:

EventHandler event_handler;

class EventHandler{
     ...

     mixin std.signals.Signal!Event;

     ...
}

mixin template EventListener(void delegate(Event) slot){
     private this()
     in{ assert(event_handler); }
     body{ event_handler.connect(&eventListener); }
     private void eventListener(Event e){ slot(e); }
}

class Foo{
     mixin EventListener!((e){ ... });
}

Sadly, this code does not compile.
My understanding (and correct me if I'm wrong) is that this does 
not compile because I cannot create such a delegate, as the scope 
that it would be in is not available at compile time (it would be 
objects instantiated from class Foo in this example).

One strategy that works is to not pass anything to the mixin 
template, and have the mixin template use a function that is 
presumed to exist. It is then the duty of the class writer to 
make sure a function of the correct name and signature exists if 
they use this mixin. However, I worry that this is poor/brittle 
design.

What is the best approach to achieve this?

Thanks, Mio
Sep 15 2014
parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Monday, 15 September 2014 at 13:50:22 UTC, 岩倉 澪 wrote:
 Hi all,

 I've been reading D Cookbook, in which the author recommends 
 the use of mixin templates to essentially hold boilerplate code 
 for classes (page 28). Referencing TDPL reaffirms this 
 strategy. With this design choice in mind, I would like to be 
 able to use a mixin template that creates a slot for me (as in 
 signals & slots) and provides a constructor that connects it to 
 the signal.

 The closest I have come is in the simplified example given 
 below:

 EventHandler event_handler;

 class EventHandler{
     ...

     mixin std.signals.Signal!Event;

     ...
 }

 mixin template EventListener(void delegate(Event) slot){
     private this()
     in{ assert(event_handler); }
     body{ event_handler.connect(&eventListener); }
     private void eventListener(Event e){ slot(e); }
 }

 class Foo{
     mixin EventListener!((e){ ... });
 }

 Sadly, this code does not compile.
 My understanding (and correct me if I'm wrong) is that this 
 does not compile because I cannot create such a delegate, as 
 the scope that it would be in is not available at compile time 
 (it would be objects instantiated from class Foo in this 
 example).

 One strategy that works is to not pass anything to the mixin 
 template, and have the mixin template use a function that is 
 presumed to exist. It is then the duty of the class writer to 
 make sure a function of the correct name and signature exists 
 if they use this mixin. However, I worry that this is 
 poor/brittle design.

 What is the best approach to achieve this?

 Thanks, Mio
would this work for you? "alias" is the usual way of taking a function as a template parameter. mixin template EventListener(alias slot)
Sep 15 2014
parent =?UTF-8?B?IuWyqeWAiSDmvqoi?= <mio.iwakura gmail.com> writes:
On Monday, 15 September 2014 at 21:37:50 UTC, John Colvin wrote:
 would this work for you? "alias" is the usual way of taking a 
 function as a template parameter.

 mixin template EventListener(alias slot)
Ah, thanks for the help! That works great. :)
Sep 16 2014