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









"Michael" <pr m1xa.com> 