Re: Defining event handlers for function, method, or shared method
On 01/26/2016 11:42 AM, tcak wrote: >> struct S { >> void memberFunction() { >> } >> } >> auto s = S(); >> >> auto memberClosure(ref S s) { >> return () => s.memberFunction(); >> } >> >> events ~= new ConcreteEvent!(() => memberClosure(s), >> () => writeln("stop"), >> bar); >> >> events.each!(e => e.stop); >> } >> >> Ali > Hmm. Your example works fine for functions, but I can't pass a method > instead of function as alias. That's why I used a closure in the example. > Check my example: > > > import std.socket; > > class EventClass{ > public void eventHandlerMethod(){ > writeln("Barking from method"); > } > } > > class Generator(alias eventHandler){ > public void bark(){ > eventHandler(); > } > } > > public void eventHandlerFunc(){ > writeln("Barking from function"); > } > > void main(){ > auto events = new EventClass; > > auto gen1 = new Generator!( eventHandlerFunc )(); > auto gen2 = new Generator!( events.eventHandlerMethod )(); As far as I know, just the member function name cannot be used that way. The problem boils down to how to create a type (or an alias) that will call a specific member function of a given object. One way is to have a dedicated type that always call foo(): import std.stdio; class C { void foo() { writeln("foo called"); } } class FooCaller { C c; this (C c) { this.c = c; } void call() { c.foo();// hard-coded to call foo() } } void main() { auto f = new FooCaller(new C()); f.call(); } The following one creates a lambda (closure in this case?) that allows the user to pick which member function to call. Admittedly, CallableCaller() is not really needed in this example but it demonstrates how "a member function call on a specific object" can be passed as an alias template parameter: import std.stdio; class C { void foo() { writeln("foo called"); } } class CallableCaller(alias closure) { void call() { closure(); } } void main() { auto c = new C(); auto f = new CallableCaller!(() => c.foo()); f.call(); } Ali
Re: Defining event handlers for function, method, or shared method
On Tuesday, 26 January 2016 at 19:22:58 UTC, Ali Çehreli wrote: On 01/26/2016 10:41 AM, tcak wrote: > I need/want this class to be able to bind > a function, a method, or a shared method. From the perspective of class > design, there shouldn't be any > difference. Its purpose is to let know about the event, not to care > about how the event > handler is designed. If I understand the problem correctly, an interface can define the interface and a templated class can provide the differences: import std.stdio; import std.algorithm; interface Event { void start(); void stop(); void itemAdded( size_t itemIndex ); } class ConcreteEvent(alias onStart, alias onStop, alias onItemAdded) : Event { void start() { onStart(); } void stop() { onStop(); } void itemAdded(size_t itemIndex) { itemAdded(itemIndex); } } void fooStart() { } void fooStop() { } void fooItemAdded(size_t itemIndex) { } void bar(size_t itemIndex) { } void main() { Event[] events; events ~= new ConcreteEvent!(fooStart, fooStop, fooItemAdded); struct S { void memberFunction() { } } auto s = S(); auto memberClosure(ref S s) {On 01/26/2016 10:41 AM, tcak wrote: > I need/want this class to be able to bind > a function, a method, or a shared method. From the perspective of class > design, there shouldn't be any > difference. Its purpose is to let know about the event, not to care > about how the event > handler is designed. If I understand the problem correctly, an interface can define the interface and a templated class can provide differences: import std.stdio; import std.algorithm; interface Event { void start(); void stop(); void itemAdded( size_t itemIndex ); } class ConcreteEvent(alias onStart, alias onStop, alias onItemAdded) : Event { void start() { onStart(); } void stop() { onStop(); } void itemAdded(size_t itemIndex) { itemAdded(itemIndex); } } void fooStart() { } void fooStop() { } void fooItemAdded(size_t itemIndex) { } void bar(size_t itemIndex) { } void main() { Event[] events; events ~= new ConcreteEvent!(fooStart, fooStop, fooItemAdded); struct S { void memberFunction() { } } auto s = S(); auto memberClosure(ref S s) { return () => s.memberFunction(); } events ~= new ConcreteEvent!(() => memberClosure(s), () => writeln("stop"), bar); events.each!(e => e.stop); } Ali return () => s.memberFunction(); } events ~= new ConcreteEvent!(() => memberClosure(s), () => writeln("stop"), bar); events.each!(e => e.stop); } Ali Hmm. Your example works fine for functions, but I can't pass a method instead of function as alias. Check my example: import std.socket; class EventClass{ public void eventHandlerMethod(){ writeln("Barking from method"); } } class Generator(alias eventHandler){ public void bark(){ eventHandler(); } } public void eventHandlerFunc(){ writeln("Barking from function"); } void main(){ auto events = new EventClass; auto gen1 = new Generator!( eventHandlerFunc )(); auto gen2 = new Generator!( events.eventHandlerMethod )(); gen1.bark(); gen2.bark(); } Error is given on "auto gen2 = ..." in main function due to passing method. I guess because it is runtime normal compile time information. I was looking for something like to be defined in the class Generator: public DelegateOnStart eventOnStart; So I could set eventOnStart as either function pointer, method pointer, or shared method pointer. To be able to support three of them, for every event, I need to define another variable, another alias, and while calling, check whichever variable (delegate pointer) is set, and call that one. I hope I am making it clear why it turns into mess.
Re: Defining event handlers for function, method, or shared method
On Tuesday, 26 January 2016 at 19:42:42 UTC, tcak wrote: On Tuesday, 26 January 2016 at 19:22:58 UTC, Ali Çehreli wrote: [...] Hmm. Your example works fine for functions, but I can't pass a method instead of function as alias. Check my example: [...] Edit: ... "I guess because it is runtime information, not compile time" ...
Re: Defining event handlers for function, method, or shared method
What a lousy copy+paste mistake that was. I am glad no credit card number leaked there. :p On 01/26/2016 11:22 AM, Ali Çehreli wrote: > class ConcreteEvent(alias onStart, alias onStop, alias onItemAdded) : > void itemAdded(size_t itemIndex) { > itemAdded(itemIndex); > } That call should have been onItemAdded(). Ali
Re: Defining event handlers for function, method, or shared method
On 01/26/2016 10:41 AM, tcak wrote: > I need/want this class to be able to bind > a function, a method, or a shared method. From the perspective of class > design, there shouldn't be any > difference. Its purpose is to let know about the event, not to care > about how the event > handler is designed. If I understand the problem correctly, an interface can define the interface and a templated class can provide the differences: import std.stdio; import std.algorithm; interface Event { void start(); void stop(); void itemAdded( size_t itemIndex ); } class ConcreteEvent(alias onStart, alias onStop, alias onItemAdded) : Event { void start() { onStart(); } void stop() { onStop(); } void itemAdded(size_t itemIndex) { itemAdded(itemIndex); } } void fooStart() { } void fooStop() { } void fooItemAdded(size_t itemIndex) { } void bar(size_t itemIndex) { } void main() { Event[] events; events ~= new ConcreteEvent!(fooStart, fooStop, fooItemAdded); struct S { void memberFunction() { } } auto s = S(); auto memberClosure(ref S s) {On 01/26/2016 10:41 AM, tcak wrote: > I need/want this class to be able to bind > a function, a method, or a shared method. From the perspective of class > design, there shouldn't be any > difference. Its purpose is to let know about the event, not to care > about how the event > handler is designed. If I understand the problem correctly, an interface can define the interface and a templated class can provide differences: import std.stdio; import std.algorithm; interface Event { void start(); void stop(); void itemAdded( size_t itemIndex ); } class ConcreteEvent(alias onStart, alias onStop, alias onItemAdded) : Event { void start() { onStart(); } void stop() { onStop(); } void itemAdded(size_t itemIndex) { itemAdded(itemIndex); } } void fooStart() { } void fooStop() { } void fooItemAdded(size_t itemIndex) { } void bar(size_t itemIndex) { } void main() { Event[] events; events ~= new ConcreteEvent!(fooStart, fooStop, fooItemAdded); struct S { void memberFunction() { } } auto s = S(); auto memberClosure(ref S s) { return () => s.memberFunction(); } events ~= new ConcreteEvent!(() => memberClosure(s), () => writeln("stop"), bar); events.each!(e => e.stop); } Ali return () => s.memberFunction(); } events ~= new ConcreteEvent!(() => memberClosure(s), () => writeln("stop"), bar); events.each!(e => e.stop); } Ali
Defining event handlers for function, method, or shared method
In many multi threading module designs of mine, I generally design a base class, and this class have some events. Exempli gratia: void eventOnStart(); void eventOnStop(); void eventOnItemAdded( size_t itemIndex ); There is this problem though. I need/want this class to be able to bind a function, a method, or a shared method. From the perspective of class design, there shouldn't be any difference. Its purpose is to let know about the event, not to care about how the event handler is designed. If I want handlers to be functions, I design it like, public alias EventOnStart = void function(); public EventOnStart eventOnStart; If it is for normal methods, design becomes like, public alias EventOnStart = void delegate(); For shared methods, it becomes, public alias EventOnStart = void delegate() shared; As you will guess, to be able to support any of those three, it becomes so complex. Is there any way generalise to support three of them without making this any complex? A secondary thing, this is not D related though, whether there is any different approach for event listener design like Observer pattern but with little overhead and complexity?