Overview
If an event returns a result then some mechanism must be used to
determine what the final result of the invocation is in case more than
one handler is invoked. In SPIN, the result handling protocol
is specified as a procedure (called result handler ) installed
to process handlers' results. Results from all the handlers are
passed to that procedure one by one as each of the invoked handlers
return, and the procedure returns the final result of the
invocation. If no result handler is installed then the result from
the last invoked handler is returned as the final result of event
invocation.
The dispatcher raises an exception in case no handler is invoked in
response of raising an event that should return a result. Otherwise
an unspecified result would be returned violating typesafety of
invocation. To avoid the exception, and return a meaningful result in
this case, a handler (called default handler ) can be
installed to run in case no other handler is called.
Because all the callers and handlers depend on result handler and the
default handler, they can be changed only by the primary implementation
module for that event.
The default state of result handling is no result handler and no
default handler.
Interface
PROCEDURE InstallResultHandler (event : PROCANY;
handler : PROCANY;
module : RTCode.Module;
closure : REFANY := NIL)
RAISES { Error };
PROCEDURE InstallDefaultHandler (event : PROCANY;
handler : PROCANY;
module : RTCode.Module;
closure : REFANY := NIL)
RAISES { Error };
Typing rules
The dispatcher dynamically checks the types of result and default
handlers at the time of their installation according to the following
rules:
- Procedure types:
- default handler and result handler must be procedures (be of type
PROCANY) and must be legal.
- Taking closure:
- a handler must take a closure is the closure argument is not
NIL,
- a handler can take a closure if the closure argument is
NIL,
- No closure:
- a default handler that does not take a closure must have the same type as
the event,
- a result handler that does not take a closure must take two
arguments of the same type as the result of the event and
return a result of the same type as the result of the event.
- With closure:
- if a default or result handler takes a closure than it must have an
additional argument (first, before all other arguments) of the
type which is a subtype of REFANY,
- Closure:
- a closure argument must be a subtype of the type of the first
argument of the corresponding procedure argument.
Usage
A result handler is installed using the InstallResultHandler
procedure in the Dispatcher interface and the default handler
is installed using the InstallDefaultHandler procedure in that
interface. Their arguments are the event for which the handler is
being installed, the handler, and the identification of a primary
implementation module for that event. Optionally, a closure may be
added for the handler. Both procedures raise an exception if the
module argument is not the primary implementation module for the
event, if the types of the event, the handler, and the closure do not
match, or if either the event or the handler is not a legal procedure.
If NIL is passed as either of the handlers then the default
state of result handling is reinstated.
Example
Consider an event that returns a BOOLEAN result. The module
that implements the event installs the procedure HandleResult
as a result handler to ensure that the final result of the event
invocation or a logical OR and DefaultResult as the
default handler to ensure that FALSE is returned if no handler
is invoked as result or event raise.
MODULE Example;
PROCEDURE Event(...): BOOLEAN =
BEGIN
...
END Event;
PROCEDURE HandleResult(result: BOOLEAN; prevResult: BOOLEAN): BOOLEAN =
BEGIN
RETURN result OR prevResult;
END HandleResult;
PROCEDURE DefaultResult(...): BOOLEAN =
BEGIN
RETURN FALSE;
END DefaultResult;
BEGIN
Dispatcher.InstallResultHandler(Event, HandleResult, THIS_MODULE());
Dispatcher.InstallDefaultHandler(Event, DefaultResult, THIS_MODULE());
END Example.
Przemek Pardyak,
May 20th, 1996