In order to support fully generalised and sound runtime adaptability throughout all possible design patterns, Dana does not include the concept of self-references from objects. An object cannot therefore use a keyword such as this to pass a reference to its own instance to another object.
Instead, Dana includes an event model to support design patterns that involve callback-style behaviour, where one object wishes to be notified of something that has happened in another object.
Dana's event model is composed of event sources and event sinks together with the operations sinkevent and emitevent.
Any interface can declare an event source from which notifications are emitted. This is done as follows:
interface MyInterface {
MyInterface()
event funEvent()
}
An object implementing this interface can produce events using the emitevent operator:
component provides MyInterface requires time.Timer timer {
void eventProducer()
{
while (true)
{
timer.sleep(10000)
emitevent funEvent()
}
}
MyInterface:MyInterface()
{
asynch::eventProducer()
}
}
An object can then receive notifications from this event source by declaring an event sink and using the sinkevent operation as follows:
uses lang.EventData
component provides App requires io.Output out, MyInterface {
eventsink MyEvents(EventData ed)
{
if (ed.type == MyInterface.[funEvent])
{
out.println("play time!")
}
}
int App:main(AppParam params[])
{
MyInterface a = new MyInterface()
sinkevent MyEvents(a)
this.thread.wait()
return 0
}
}
As well as the event type identifier, the EventData type also includes a source field which provides a reference to the object that generated the event, and a details field which refers to a Data instance offering additional details relevant to that event.
Event declarations in interfaces can optionally have a single parameter of any data type:
interface MyInterface {
MyInterface()
event funEvent(String k)
}
When emitevent is then used, we can pass in an instance of this data type as a parameter in the form emitevent funEvent(new String("hi")), which is then available in the details field of the EventData instance delivered to the event sink.
Note that event sinks are single-threaded, such that multiple simultaneous events received at a sink are placed into a queue. Once the event sink returns from handling the first event in the queue, the event sink is called again for the second item, and so on. If an event queue becomes full due to the speed of events arriving exceeding the speed of events being handled, the event queue will drop any further events that arrive until more space becomes available.
Finally, each event sink can only have one copy of the same event registered from the same object instance. If the above example used the line sinkevent MyEvents(a) twice, Dana would ignore the second sinkevent command and the associated event sink would only fire once per event. To stop receiving a specific event from an object, we use the instruction stopevent MyEvents(a).