User Tools

Site Tools

Command disabled: revisions

In order to support fully generalised 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.

Dana provides two mechanisms to assist in creating the kinds of design pattern for which self-references are often used. These are unique object identifiers and an event model.

Unique Object Identifiers

Every Dana object inherently supports the getID() function, as declared in the Object type. This function returns a unique identifier for that object as a string. The identifier returned is guaranteed not to be associated with any other object instance that exists. However, Dana does re-cycle object identifiers when objects get cleaned up. Over time you may therefore see the same object identifier being used across different objects due to old objects being garbage collected and their IDs being assigned to newer objects; however no two live objects will ever have the same identifier at the same time.

Because an object can access its own unique ID, by simply calling getID(), this means that objects can pass their own identifier to other objects, for example to have that ID compared against a list of object IDs stored at such other objects.

The Event Model

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 {
   event funEvent()

An object implementing this interface can produce events using the emitevent operation:

component provides MyInterface requires time.Timer timer {
   void eventProducer()
      while (true)
         emitevent funEvent()

An object can then receive notifications from this event source by declaring an event sink and using the sinkevent operation as follows:

uses events.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)
      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. To do this, a parameter of the event can be declared in the interface, and emitevent can then pass in an instance of this data type, which is then referenced by 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).

events-ids-references.txt · Last modified: 2019/04/05 07:25 by barryfp

Page Tools