digitalmars.D.learn - [Question] About mixin, template and alias
- Michael (49/49) Sep 22 2013 /////// fire.d
- monarch_dodra (11/60) Sep 22 2013 This:
- Michael (1/11) Sep 22 2013 Why like "static"?
- monarch_dodra (10/23) Sep 22 2013 Because that is the definition of inline initialization.
- monarch_dodra (2/3) Sep 22 2013 http://d.puremagic.com/issues/show_bug.cgi?id=11107
/////// fire.d import std.stdio; alias void delegate() EventHandler; class Event(T) { private T[] _events; public void opOpAssign(string op)(T param) if (op == "~") { writeln(param.funcptr); _events ~= param; } public void opCall(ParamType ...)(ParamType params) { emit(params); } protected void emit(ParamType ...)(ParamType params) { foreach (event; _events) event(params); } } mixin template AddEvent(DelegateType, string member) { auto eventObserver = new Event!DelegateType(); mixin("alias eventObserver " ~ member ~ ";"); } class Fire { public mixin AddEvent!(EventHandler, "click"); } /////// water.d import std.stdio; import fire; class Water : Fire { } void main() { auto fire = new Fire(); auto water = new Water(); water.click ~= () { writeln("Water!"); }; fire.click ~= () { writeln("Fire!"); }; fire.click(); } Output: Water! Fire! Someone can explain me a behaviour of above code? Why not "Fire!" only?
Sep 22 2013
On Sunday, 22 September 2013 at 18:31:20 UTC, Michael wrote://///// fire.d import std.stdio; alias void delegate() EventHandler; class Event(T) { private T[] _events; public void opOpAssign(string op)(T param) if (op == "~") { writeln(param.funcptr); _events ~= param; } public void opCall(ParamType ...)(ParamType params) { emit(params); } protected void emit(ParamType ...)(ParamType params) { foreach (event; _events) event(params); } } mixin template AddEvent(DelegateType, string member) { auto eventObserver = new Event!DelegateType(); mixin("alias eventObserver " ~ member ~ ";"); } class Fire { public mixin AddEvent!(EventHandler, "click"); } /////// water.d import std.stdio; import fire; class Water : Fire { } void main() { auto fire = new Fire(); auto water = new Water(); water.click ~= () { writeln("Water!"); }; fire.click ~= () { writeln("Fire!"); }; fire.click(); } Output: Water! Fire! Someone can explain me a behaviour of above code? Why not "Fire!" only?This: //---- auto eventObserver = new Event!DelegateType(); //---- Does not do what you think it does: It *statically* initializes "eventObserver" to the *single* "new Event!DelegateType();". SO basically, all your instances are sharing the same Event. I'm surprised this compiles at all, what with Fire.init depending on a run-time call, but apparently, dmd is "smart enough" to do the allocation at compile time.
Sep 22 2013
This: //---- auto eventObserver = new Event!DelegateType(); //---- Does not do what you think it does: It *statically* initializes "eventObserver" to the *single* "new Event!DelegateType();". SO basically, all your instances are sharing the same Event. I'm surprised this compiles at all, what with Fire.init depending on a run-time call, but apparently, dmd is "smart enough" to do the allocation at compile time.Why like "static"?
Sep 22 2013
On Sunday, 22 September 2013 at 21:18:13 UTC, Michael wrote:Because that is the definition of inline initialization. Basically, every type (struct/class) has a ".init" state, which is a compile-time known static initial value. So when you write "auto a = new A;" It means a resolves to the *value* which is the result of "new A". This is not to be confused with the *expression*. In any case, I think the code is wrong to begin with, since you are basically using a non shared to access a non-TLS global. I'm filing a bug report right now.This: //---- auto eventObserver = new Event!DelegateType(); //---- Does not do what you think it does: It *statically* initializes "eventObserver" to the *single* "new Event!DelegateType();". SO basically, all your instances are sharing the same Event. I'm surprised this compiles at all, what with Fire.init depending on a run-time call, but apparently, dmd is "smart enough" to do the allocation at compile time.Why like "static"?
Sep 22 2013
On Monday, 23 September 2013 at 06:31:01 UTC, monarch_dodra wrote:I'm filing a bug report right now.http://d.puremagic.com/issues/show_bug.cgi?id=11107
Sep 22 2013
I understand. So, at least it's has interesting behaviour and big question)
Sep 23 2013
Code below shows that I would achieve: ///// fire.d alias void delegate() EventHandler; class Event(T) { private T[] _events; public void opOpAssign(string op)(T param) if (op == "~") { _events ~= param; } public void opCall(ParamType ...)(ParamType params) { this.emit(params); } protected void emit(ParamType ...)(ParamType params) { foreach (event; _events) event(params); } } mixin template AddEvent(DelegateType, string member) { private Event!DelegateType _eventObserver; property auto get() { if (_eventObserver is null) _eventObserver = new Event!DelegateType(); return _eventObserver; } void doEventObserver(ParamType ...)(ParamType params) { mixin (member ~ "()(params);"); } mixin ("alias get " ~ member ~ ";"); mixin ("alias doEventObserver do" ~ member ~ ";"); } class Fire { public mixin AddEvent!(EventHandler, "click"); } class DoubleFire { private Event!EventHandler _click; public this() { _click = new Event!EventHandler(); } property public Event!EventHandler click() { return _click; } public void doClick(ParamType ...)(ParamType params) { click()(params); } } ///// water.d import std.stdio; import fire; class Water : Fire { } void main() { Fire element; element = new Fire(); element.click ~= () { writeln("Fire!"); }; element.click()(); // Not needed with DIP 23 element = new Water(); element.click ~= () { writeln("Water!"); }; element.click()(); // Not needed with DIP 23 DoubleFire df = new DoubleFire(); df.click ~= () { writeln("Double Fire!"); }; df.doClick(); // Workaround element.doclick(); // Workaround } ///// Output Fire! Water! Double Fire! Water! Thanks)
Sep 23 2013