Action Walkthrough, part 4

While not really part of the Action walk-through, per se, the sequence of events involving Messages still involves Actions, because Model Actions implement message behaviors. Therefore, nearly all messages ultimately result invoking some (Model) Action.

This article details the sequence of events involving Message objects.

The previous article described how the @hypot Actor invoked its Action (see first article in the series for that Action and Actor). Key here was how an Action clause sends an X: message to its exec-list object. This executes (sends an X: message to) any items on that list.

The @hypot Action (being a single-clause Action) has a single execution list, and that list had only one object — an expression (which contained multiple objects). The expression is shown below:

set:h @sqrt add: mul:a a mul:b b

The list sees only a single object, the set: Message object. That object has a target, the (reference to the) h Instance object, and a parameter, the @sqrt Actor object.

The Actor object has a single parameter, the add: Message object, and that object has a target, a mul: Message object, and a parameter, another mul: Message object. Both mul: Message objects have target and parameter objects (which happen to be identical, effectively making the “multiply” operation a “squaring” operation).

The basic sequence of events for any Message object is the same:

  1. Send a Q: message to the parameter object.
  2. Send our message to the target object.
  3. Pop result object.
  4. Send received message to result object.

The first step causes the parameter object to push a value onto the stack. That object is presumably used by the target object when it processes our message. The final step applies whatever message we received to the result.

This causes a cascade of events as all the Messages (and single Actor) in the expression perform the above steps. That cascade goes like this:

  1. Execution list sends Q: message to set: Message object.
  2. set: Message object sends Q: message to @sqrt Actor object.
  3. @sqrt Actor object invokes @sqrt Action object.
  4. @sqrt Action sends Q: message to add: Message object.
  5. add: Message object sends Q: message to (second) mul: Message object.
  6. mul: Message object sends Q: message to b Instance object.
  7. b Instance object pushes its address onto the stack.
  8. mul: Message object sends its message to b Instance object.
  9. b Instance object processes mul: message, consumes a stack object and pushes result object (b squared) onto the stack.
  10. mul: Message pops result object (into T1) and applies received Q: message.
  11. Result object pushes its address (T1) onto the stack.
  12. add: Message object sends its message to the (first) mul: Message object.
  13. mul: Message object sends Q: message to a Instance object.
  14. a Instance object pushes its address onto the staack.
  15. mul: Message object sends its message to a Instance object.
  16. a Instance object processes mul: message, consumes a stack object and pushes a result object (a squared) onto the stack.
  17. mul: Message pops result object (into T2) and applies received add: message.
  18. Result object (a squared) processes add: message, consumes a stack object (b squared) and pushes result object (a-b-sum) onto the stack.
  19. add: Message pops result object (into T3) and applies received Q: message.
  20. Result object pushes its address (T3) onto the stack.
  21. @sqrt Action pops result object (a-b-sum), performs square root operation and pushes result object (hypot) onto the stack.
  22. @sqrt Actor pops result object (into T4) and applies received Q: message.
  23. Result object pushes its address (T4) onto the stack.
  24. set: Message object sends its message to the h Instance object.
  25. h Instance object processes the set: message, consumes a stack object and pushes a result object (h‘s address) onto the stack.
  26. set: Message pops result object (into T5) and does not apply the received X: message.

While that may seem complicated, it’s nothing more than multiple nestings of the four steps listed above. (The details of the Actor-Action behavior was described in the previous article.)

Nearly all messages ultimately invoke behaviors in Instance objects. (One rare exception is the W: message, which applies to all objects and specifies they should push their address to the stack.) Some meta-types, Models and Actions for example, don’t really process any messages.

Actors and Messages apply nearly all received messages to their result object (whatever that might be) and also don’ t have much in the way of message-related behavior themselves.

Only Instance objects have rich message behavior sets, and each behavior is implemented with an Action object in the Instance object’s Model object. So, for example, the add behavior for *int objects — that is, for Instance objects that are instances of the *int Model object — is an Action in that Model (a Model Action).

With Instance objects, the Q: message has the same semantic as the W: message — a request to push the Instance’s address onto the stack. As such, both messages are handled at a high level. All other messages, including the X: message (which means initialize), are passed on to the object for processing:

1. An Instance object receives a message.

2. The Instance object calls the dispatch() method of its linked Model object and passes in itself (as “this”) and the received message.

3. The Model object uses the message to find a matching Action object to handle it. If it cannot (and if no matching Action object is found in any parent Model object if such exist), the Model object throws an “Unknown Message” Exception.

4. The Model object determines whether the Action takes a parameter in addition to this (the invoking object), and — if so — pops an object (as “that”) off the stack for that use.

5. The Model object builds the clause object, which will be either (mesg, this) or (mesg, this, that), depending on whether a parameter is needed.

6. The Model object invokes the Action object and passes in the clause object.

7. The Action object executes, consumes its inputs and pushes a result object onto the stack.

8. The Action object exits to the Model object which exits to the Instance object which exits and returns control to whomever passed it the message. At this point the result of the Instance processing the message is on the stack.

Advertisements
%d bloggers like this: