Events

Events are a special kind of Member in a Class or Record that allow other parts of the code to subscribe to notifications about certain, well, events in the class.

An event is very similar to a Block type Field, but rather than just storing a single block reference, events are "multi-cast". This means they maintain a list of subscribers, and when calling the event, all subscribers will get a callback.

Platform Considerations

Although events are most commonly used on .NET and both Cocoa and Java have different paradigms to deal with similar concepts (such as regular Blocks, Delegate Classes (not to be confused with .NET's use of the term) and Anonymous Interfaces), events are supported on all platforms.

Event Declaration Syntax

A simple event declaration consists of the event keyword, followed by a name for the event and the type of Block that can be used to subscribe to the event. The block type can be a named Alias, or an explicit block declaration:

event ButtonClick: EventHandler;       // EventHandler is a named block defined elsewhere
event Status: block(aMessage: String);

Just as with Stored Properties, with this short syntax the compiler will take care of creating all the infrastructure for the event, including a private variable to store subscribers, and add and remove methods.

Optionally, an add and remove clause can be provided to explicitly name the methods responsible for adding and removing handlers. These methods must then be declared and implemented separately, and they must take a single parameter of the same type as the event (This, too, is comparable to the read and write statements for a Property). It is then up to the implementation of these methods to handle the subscription/unsubscription logic.

  private
    method AddCallback(v: EventHandler);
    method RemoveCallback(v: EventHandler);
  public
    event Callback: EventHandler add AddCallback remove RemoveCallback;

Alternatively, on .NET only, a block field to be used for storage can be provided via the block (or legacy delegate) keyword:

  private
    fCallback: EventHandler;
  public
    event Callback: EventHandler block fCallback;

Subscribing to or Unsubscribing from Events

Externally, code can subscribe or unsubscribe from an event by adding or removing handlers. This is done with the special += and -= operators, to emphasize that events are, by default, not a 1:1 mapping, but that each event can have an unlimited number of subscribers.

method ReactToSomething(aEventArgs: EventArgs);

//...

myObject.Callback += @ReactToSomething

//...

myObject.Callback -= @ReactToSomething

Of course, any compatible Block can be used to subscribe to an event – be it a method of the local type, as in the example above or e.g. an Anonymous Method.

Please refer to the Event Access Expression topic for more details.

Raising Events

An event can be raised by simply calling it like a Block or Method. Before doing so, one should ensure that at least one subscriber has been added, because firing a unassigned event, just as calling a nil block, will cause a NullReferenceException.

The assigned() System Function or comparison to nil can be used to check if an event is assigned.

if assigned(Callback) then
  Callback();

By default, only the type that defines the event can raise it, regardless of the visibility of the event itself. See more on this in the following section.

Visibility

The visibility of events is governed by the Visibility Section of the containing type the event is declared in, or the Visibility Modifiers applied to the event.

This visibility extends to the ability to add and remove subscribers, but not to the ability to raise (or fire off) the event, which can be controlled by the raise statement, described below.

Optionally, separate visibility levels can be provided for the add, remove and raise statements. These will override the general visibility of the event itself:

event Callback: EventHandler public add AddCallback private remove RemoveCallback;

Raise Statements

Optionally, a raise statement combined with an (also optional) visibility level can be specified, in order to extend the reach of who can raise (or fire off) the event. By default, the ability to raise an event is private, and limited to the class that declares it.

event Callback: EventHandler protected raise;

In the example above, raising the event (normally private) is propagated to a protected action, meaning it is now available to descendant classes.

Static/Class Events

Like most type members, events are by default defined on the instance – that means the event can be called on and will execute in the context of an instance of the class. A event can be marked as static by prefixing the event declaration with the class keyword, or by applying the static Member Modifier:

class event SomethingChanged: EventHandler;       // static event on the class itself
event SomethingElseChanged: EventHandler; static; // also static event on the class itself

Virtuality

The Virtuality of events can be controlled by applying one of the Virtuality Member Modifiers.

event SomethingChanged; virtual;

Events can be marked as abstract, if a descendant class must provide the implementation. Abstract events (and events in Interfaces may not define an add, remove or raise statement.

event OnClick: EventHandler; abstract;

Other Modifiers

A number of other Member Modifiers can be applied to events.

  • deprecated Makes an event deprecated.
  • implements   ISomeInterface.SomeMember (See Explicit Interface Implementations).
  • locked Like locked on, with self as an expression.
  • locked on   Expression executes a lock on the expression around the accessors of this event.
  • mapped to (See Mapped Members).
  • optional (Interface members only).
  • unsafe Allows the use of unsafe types in event signatures.

See Also