Thread overview | |||||||||
---|---|---|---|---|---|---|---|---|---|
|
September 22, 2013 [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
/////// 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? |
September 22, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michael | 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.
|
September 22, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | > 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"?
|
September 23, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to Michael | On Sunday, 22 September 2013 at 21:18:13 UTC, Michael wrote:
>> 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"?
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.
|
September 23, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | 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 |
September 23, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | I understand. So, at least it's has interesting behaviour and big question) |
September 23, 2013 Re: [Question] About mixin, template and alias | ||||
---|---|---|---|---|
| ||||
Posted in reply to monarch_dodra | 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) |
Copyright © 1999-2021 by the D Language Foundation