next up previous

9.4 DEFMESSAGE-HANDLER CONSTRUCT

Objects are manipulated by sending them messages via the function send. The result of a message is a useful return-value or side-effect. A defmessage-handler is a construct for specifying the behavior of a class of objects in response to a particular message. The implementation of a message is made up of pieces of procedural code called message-handlers (or handlers for short). Each class in the class precedence list of an object's class can have handlers for a message. In this way, the object's class and all its superclasses share the labor of handling the message. Each class's handlers handle the part of the message which is appropriate to that class. Within a class, the handlers for a particular message can be further subdivided into four types or categories: primary, before, after and around. The intended purposes of each type are summarized in the chart below:


Type         Role for the Class

primary   Performs the majority of the work for the
          message

before    Does auxiliary work for a message before the
                   primary handler executes

after     Does auxiliary work for a message after the
                   primary handler executes

around    Sets up an environment for the execution of the
          rest of the handlers



Before and after handlers are for side-effects only; their return values are always ignored. Before handlers execute before the primary ones, and after message-handlers execute after the primary ones. The return value of a message is generally given by the primary message-handlers, but around handlers can also return a value. Around message-handlers allow the user to wrap code around the rest of the handlers. They begin execution before the other handlers and pick up again after all the other message-handlers have finished.

A primary handler provides the part of the message implementation which is most specific to an object, and thus the primary handler attached to the class closest to the immediate class of the object overrides other primary handlers. Before and after handlers provide the ability to pick up behavior from classes that are more general than the immediate class of the object, thus the message implementation uses all handlers of this type from all the classes of an object. When only the roles of the handlers specify which handlers get executed and in what order, the message is said to be declaratively implemented. However, some message implementations may not fit this model well. For example, the results of more than one primary handler may be needed. In cases like this, the handlers themselves must take part in deciding which handlers get executed and in what order. This is called the imperative technique. Around handlers provide imperative control over all other types of handlers except more specific around handlers. Around handlers can change the environment in which other handlers execute and modify the return value for the entire message. A message implementation should use the declarative technique if at all possible because this allows the handlers to be more independent and modular.

A defmessage-handler is comprised of seven elements: 1) a class name to which to attach the handler (the class must have been previously defined), 2) a message name to which the handler will respond, 3) an optional type (the default is primary), 4) an optional comment, 5) a list of parameters that will be passed to the handler during execution, 6) an optional wildcard parameter and 7) a series of expressions which are executed in order when the handler is called. The return-value of a message-handler is the evaluation of the last expression in the body.

Syntax

Defaults are outlined.

(defmessage-handler <class-name> <message-name>
                   [<handler-type>] [<comment>]
    (<parameter>* [<wildcard-parameter>])
    <action>*)
<handler-type>        ::= around | before | primary | after
<parameter>           ::= <single-field-variable>
<wildcard-parameter>  ::= <multifield-variable>

Message-handlers are uniquely identified by class, name and type. Message-handlers are never called directly. When the user sends a message to an object, CLIPS selects and orders the applicable message-handlers attached to the object's class(es) and then executes them. This process is termed the message dispatch.

Example

CLIPS> (clear)
CLIPS> (defclass A (is-a USER) (role concrete))
CLIPS>
(defmessage-handler A delete before ()
     (printout t "Deleting an instance of the class A..." crlf))
CLIPS>
(defmessage-handler USER delete after ()
   (printout t "System completed deletion of an instance."
               crlf))
CLIPS> (watch instances)
CLIPS> (make-instance a of A)
==> instance [a] of A
[a]
CLIPS> (send [a] delete)
Deleting an instance of the class A...
<== instance [a] of A
System completed deletion of an instance.
TRUE
CLIPS> (unwatch instances)
CLIPS>

9.4.1 Message-handler Parameters

9.4.2 Message-handler Actions

9.4.3 Daemons

9.4.4 Predefined System Message-handlers



next up previous