BOOL Message objects take the place of operators in other languages. They bind expressions together and invoke behaviors in objects. Messages are the only way to accomplish anything in BOOL. The
X: Message invokes code objects, and the
Q: Message puts object values on the stack for manipulation.
A Message object sends a message to its target object (which can be anything). The target object handles the message, ultimately causing some action to occur. In nearly all cases, the action has a result object, which is returned on the stack. The key exception is the
X: message, which has no result.
If the target is an Instance object, it invokes its Model, passing both itself and the message. The Model dispatches the message and the Instance to a Model Action that implements the behavior specified by the message. Models generally support a rich set of behaviors for their Instances.
If the target is some other meta-type, the behavior set is more sparse. Most meta-types do not handle most messages (sending them one results in a run-time exception). In particular, Models and Actions don’t have a rich action set.
When a Message is the target object, it passes the received message to its result object. Actor objects have a similar protocol: they pass the received message to the Action result object returned on the stack.
Syntaxmessage: target parameter
message: target ;
add: X Y abs:X; open:file RD,TEXT,CRLF t:foo
A Message is a name followed by a colon. (As usual in BOOL names, a hyphen is a legal name character.) A Message always has a target object. No space is required between the Message and its target.
A Message either has a parameter object or uses the semi-colon as a “null” parameter. The single exception is the single-letter System Messages, which are all singletons (i.e. they have only a target, no parameter).
If the Model Action that implements a Message takes multiple parameters, then the Message parameter is a list of these.
There are several System Messages that are typically handled at a low level by the SendMessage() dispatcher. These messages all consist of a single letter, and all implicitly are singleton messages — they have only a target, no parameter(s). All objects respond to all System Messages.
X: — Execute, but do not leave any result on the stack. This may be a null operation for some meta-types (such as Actions and Models).
Q: — Query and leave result on the stack. For Instances (and some others), this acts like the
W: message (see below). For Message and Actor objects, it causes evaluation and a result object on the stack.
W: — Where are you; put your address on the stack. This gets an address without evaluating the addressed object (unlike the
M: — Model; put Model’s address on the stack. This works differently depending on the meta-type. Instances push their Model’s address, which is the intended use. Actors push their Action’s address (which can be helpful). Everything else (the Message object itself, for example) returns Null.
F: — True and False; evaluate target’s truth and put a Boolean on the stack. These messages work like the
Q: message in that they force evaluation, but they also ask the target to return a Boolean True/False value on the stack.
The basic algorithm for Messages is:
Message::SendMessage (msg_obj, rcv_msg): // Send a Q: Message to param(s)... for-each param in msg_obj.params: SendMessage(param, 'Q', ctx) // Send the Message object's message to the target... SendMessage(msg_obj.target, msg_obj.message, ctx) // Get the result and apply received-message... result = PStack.pop() CallFrame.SetValue(msg_obj.result, result, ctx) if rcv_msg != 'X': SendMessage(msg_obj.result, rcv_msg, ctx)
The TEMP object associated with a MSG object acts as the code address for the dynamic object created by the target’s response to the message. The last lines above pop that result from the stack and apply it to the TEMP object.
X: message is ignored; the popped value is effectively discarded. A
Q: message pushes the TEMP object’s address back to the stack (as opposed to the data object that was just popped off the stack into the associated Call Frame slot).
(TEMP, T_any, dx): @temp (MSG, name, target, [ parameter ], @temp, properties)
Note that a MSG object always has an associated TEMP object to receive (and provide a code address for) the result object from the target after it processes the message. (The type of the result is
T_any by default, but some circumstances allow a more specific type.)