GEOS SDK TechDocs
|
|
4.4 Declaring Objects
|
4.6 Managing Objects
@send, @call, @callsuper, @record, @dispatch, @dispatchcall, TravelOption, ObjDuplicateMessage(), ObjFreeMessage(), ObjGetMessageInfo()
Often you will have to send messages to objects throughout the system. You can send messages in several ways, but the two most basic and most frequently used involve the keywords
@call
and
@send
.
If a message is being sent across threads, you must be aware of synchronization issues. If the message does not cross thread boundaries, the kernel will link the code directly as if it were a function call. (This is an implementation difference only; you do not have to specify anything different in your code.)
The
@send
keyword causes the kernel to put the specified message into the recipient's event queue. Messages sent with
@send
may not give return values and may not take pointers to locked memory as arguments. The sender then continues executing without ever knowing whether the message was properly handled or not.
The
@call
keyword is used when the message being sent must return information to the sender. It is also used when the message must be handled immediately, before the sender is allowed to continue executing. In essence, the sender is "put to sleep" until the message has been processed, at which time the sender is woken up and may continue executing. If the message sent with
@call
is not handled (passed up the recipient's class tree and still not handled), it will return as if it had been; no error message will be returned.
The formats for
@send
and
@call
are similar. Use them like function calls. Their format is given below:
@send [,<flags>]+ \
<obj>::[{<cast2>}]<msg>(<params>*);
<ret> = @call [,<flags>]+ [{<cast>}] <obj>::\
[{<cast2>}]<msg>(<params>*);
@call
because
@send
does not return anything.
cast
.
cast2
.The flags allowed for these keywords are listed below. They are rarely used but are available.
forceQueue
@call
.
checkDuplicate
forceQueue
must also be passed. Events are checked from first (next-to-be-processed) to last. If the message is a duplicate, it will be dropped; however the
replace
flag, described below, can change this behavior.
checkLastOnly
checkDuplicate
, causing it to check only the last message in the event queue.
replace
checkDuplicate
and
checkLastOnly
by superseding the duplicate (old) event with the new one. The new event will be put in the duplicate's position in the event queue. If a duplicate is found but the
replace
flag is not passed, the duplicate will be dropped.
insertAtFront
canDiscardIfDesperate
The
@call
command can also be used within an expression in the same way a function call could. For example, the following conditional expression is valid:
if (@call MyObj::MSG_MYOBJ_TEST()) {
/* conditional code */
}
The result of the message call will be evaluated in the if statement. Note that this may not be done with
@send
because it returns nothing.
Because of the way Goc processes message calls, it is impossible to nest messages on a single line. For example, this call is illegal:
@send Obj1::MSG_THATS_PASSED_AN_INT(\ @call Obj2::MSG_THAT_RETURNS_INT());
Any such call will generate a compile-time error. Instead, you should use temporary variables to break this up into several lines, e.g.:
int i;
i = @call Obj2::MSG_THAT_RETURNS_INT();
@send Obj2::MSG_THATS_PASSED_AN_INT(i);
Often you may wish to send a message directly to an object's superclass to ensure that default behavior is implemented. Use the
@callsuper
keyword with the following format:
@callsuper <obj>::<class>::<msg>(<pars>*) [<flgs>+];
@call
and
@send
. The object block must already be locked, and must be run by the current thread of execution. (Usually an object uses
@callsuper()
to send a message to itself.)
@call
and
@send
.
@call
and
@send
.
When used on a line by itself (with no parameters or return values),
@callsuper()
passes a received message on to the superclass. This is used quite often when a subclass wants to alter existing behavior rather than replace it.
By encapsulating messages, you can set up events to be sent out at a later time. An encapsulated message can include the message to be sent, the object it should be sent to, and the parameters that should be passed. Using encapsulated messages can sometimes simplify coding.
Messages can be encapsulated with the
@record
keyword and later dispatched with
@dispatch
and
@dispatchcall
. (Though the use of
@record
does not necessitate a later
@dispatch
--there are other uses for an encapsulated event.) In addition, when the event is dispatched, you can override the values set in the encapsulated event to change the destination or the message. You can also cast the return value to another type if necessary. The formats of these three keywords are as follows:
<event> = @record <obj>::[{<cast>}]<msg>(<params>*);
EventHandle
.
null
if the destination is determined when the message is dispatched.
null
if the message is determined when it is dispatched.
@call
and
@send
) that will be sent with the dispatched message.
You may create a copy of a recorded message by means of the
ObjDuplicateMessage()
routine. To free it, call
ObjFreeMessage()
. To discover the Message and destination object associated with a recorded event, call
ObjGetMessageInfo()
.
The
@dispatch
keyword is used to dispatch an encapsulated event to its destination. This is similar to
@send
in that it can have no return values. If the event has return values, use
@dispatchcall
(below).
@dispatch [noFree] \
<nObj>::[{<cast>}]<nMsg>::<event>;
null
.
null
. Any override will be sent with the same parameters as set in the encapsulated event.
The
@dispatchcall
keyword works exactly like the
@dispatch
keyword above except that it allows the use of return values. The sender will be "put to sleep" if necessary while the recipient processes the message and will be "woken up" when the message returns.
<ret> = @dispatchcall [noFree] [{<cast>}] <nObj>::\
<nMsg>::<event>;
@dispatch
.
All message-sending keywords described in the previous sections--
@call
,
@send
,
@record
,
@dispatch
, and
@dispatchcall
--can take expressions in place of a destination object's name. Additionally, the
@dispatch
and
@dispatchcall
keywords can take expressions in place of the message name. However, if an expression is used for the message, you must use a cast type to make sure Goc knows the return and parameter types. Note, however, that casts in this case use curly braces rather than parentheses.
Goc allows you to cast a message's pass and return values. This is best explained by example:
{
int swapInt;
char c;
c = @call {MSG_1} object:: {MSG_2} MSG_X(swapInt);
}
In this case, MSG_2 takes an integer argument and MSG_1 returns a char. The casts tell Goc how MSG_X will receive parameters and return results. Goc needs the casts in those cases where MSG_X doesn't appear explicitly (perhaps it has been stored as an integer), and thus Goc would not be able to parse the parameters or return values.
When Goc tries to determine proper parameters and returns, it will look to the following sources when available. When trying to figure out parameters, it will look first for MSG_2, then MSG_X, and MSG_1 last. The first one Goc finds will determine the parameters.
@send
and
@record
don't support return values, but on a
@call
, Goc will figure out return values by looking at MSG_1, MSG_X, and finally MSG_2.
In this case, Goc will pass to fn's method like MSG_CAST_2 but will return values as MSG_CAST_1 does:
Message fn = GetMessageToCall();
c = @call {MSG_CAST_1} myObj:: {MSG_CAST_2} fn(x);
Now we pass to MSG_B like MSG_CAST_2, but return like MSG_B:
c = @call myObj:: {MSG_CAST_2} MSG_B(swapInt);
MSG_META_SEND_CLASSED_EVENT, TravelOption
You do not always need to specifically include an object as a destination for your message. In many cases, you may be able to generically address your message using a
classed event
. A classed event consists of a pre-defined
TravelOption
enumerated type and an EventHandle recorded using the @record Goc construct. The event in this case does not contain a specific object, but rather an object class.
The
TravelOption
acts as a navigator, determining along what path the message should be delivered. The object class within the classed event acts as a filter, determining if the object sent the message is an object of that class. If the object first encountered along the path dictated by the
TravelOption
is not a matching class, the classed event is passed to the next object on that path. When the class finally matches, the message will be handled by that object.
The classed event is originally dispathed from the object by sending MSG_META_SEND_CLASSED_EVENT. This message is usually sent by an object to itself. The travel options available depend on the class(es) of the object receiving the message. That is, the object receiving the message must be a sub-class of one of the following:
MetaClass
(Usable by all GEOS object classes)
TravelOption
indicates that the message should be delivered to the object block's output optr.
ProcessClass
object.
GenClass
(Usable by all generic objects)
VisClass
(Usable by all visible objects)
GenApplicationClass
(Usable by all Application objects)
To send a classed event, you must first record the event, specifying the message to send and the object class to handle the message. Then you must send MSG_META_SEND_CLASSED_EVENT--usually to yourself-- passing that handle and a
TravelOption
.
<event> = @record <objClass>::<msg>
@send self::MSG_META_SEND_CLASSED_EVENT(<event>, <TravelOption>);
Code Display 5-18 Sending a Classed Event
/* * First record the Classed event. In this case, we want an object of class * `MyFooClass' to handle MSG_FOO. We will send this classed event along the * target hierarchy. We want to begin the path at the application object, so we * will use the TO_APP_TARGET TravelOption. */
event = @record MyFooClass::MSG_FOO;
/* * Then dispatch the classed event using MSG_META_SEND_CLASSED_EVENT. */
@send self::MSG_META_SEND_CLASSED_EVENT(event, TO_APP_TARGET);
All messages, when received, contain three basic parameters: the message number (
message
), the optr of the recipient (
oself
), and a far pointer to the recipient's locked instance chunk (
pself
). This allows several shortcuts and shorthand formats for use within methods:
@callsuper;
When used in a method as above, the
@callsuper
keyword passes the received message up to the object's superclass. Use this whenever subclassing a message when the default functionality must be preserved.
<ret> = @call self::<msg>(<params>*);
Any object can send a message to itself using
@call
and "self" as the destination. The remainder of the command is the same as a normal
@call
.
<ret> = @call process::<msg>(<params>*);
Any object can send a message to its Process object with
@call
and "process" as the destination. (The Process object is the object of class
ProcessClass
.) The remainder of the command is the same as a normal
@call
.
<ret> = @call application::<msg>(<params>*);
Any object can send a message to its Application object (of class
GenApplicationClass
) with
@call
and "application" as the destination. The remainder of the command is the same as a normal
@call
.
<ret> = @call @visParent::<msg>(<params>*);
Any object in a visible tree can use
@visParent
as the destination of an
@call
command. The message will be sent to the object's parent in the visible object tree. The remainder of the command is the same as a normal
@call
.
<ret> = @call @genParent::<msg>(<params>*);
Any object in a generic tree can use
@genParent
as the destination of an
@call
command. The message will be sent to the object's parent in the generic object tree. The remainder of the command is the same as a normal
@call
.
@send @visChildren::<msg>(<params>*);
Any composite object in a visible object tree (therefore a subclass of
VisCompClass
) can send a message that will be dispatched at once to all of its children. Any message sent with
@visChildren
as the destination must be dispatched with the
@send
keyword and therefore can have no return value.
@send @genChildren::<msg>(<params>*);
Any composite object in a generic object tree (therefore a subclass of
GenClass
) can send a message that will be dispatched at once to all of its children. Any message sent with
@genChildren
as the destination must be dispatched with the
@send
keyword and therefore can have no return value.
In addition to the above shortcuts, you may also pass the optr of an object using
@<obj>
, where
<obj>
represents the name of the object. This syntax gets translated by Goc into
(optr)&<obj>
; this is similar to using the ampersand (&) to pass a pointer.
GEOS SDK TechDocs
|
|
4.4 Declaring Objects
|
4.6 Managing Objects