Note that message sending is only the same as calling an object's predicate if the object does not inherit (or import) predicate definitions from other objects (or categories). Otherwise, the predicate definition that will be executed may depend on the relationships of the object with other Logtalk entities.
Logtalk uses the following three operators for message sending:
:- op(600, xfx, ::). :- op(600, fx, ::). :- op(600, fx, ^^).
It is assumed that these operators remain active (once the Logtalk preprocessor and runtime files are loaded) until the end of the Prolog session (this is the usual behaviour of most Prolog compilers). Note that these operator definitions are compatible with the pre-defined operators in the Prolog ISO standard.
Sending a message to an object is done by using the ::/2
infix operator:
| ?- Object::Message.
The message must match a public predicate declared for the receiving object or a Logtalk/Prolog built-in predicate, otherwise an error will be thrown (see the Reference Manual for details).
In the Logtalk context, broadcasting is interpreted as the sending of the same message to a group of objects or the sending of several messages to the same object. Both needs can be achieved by using the message sending method described above. However, for convenience, Logtalk implements an extended syntax for message sending that makes programming easier in these situations.
If we wish to send several messages to the same object, we can write:
| ?- Object::(Message1, Message2, ...).
This is semantically equivalent to:
| ?- Object::Message1, Object::Message2, ... .
We can also write:
| ?- Object::(Message1; Message2; ...).
This will be semantically equivalent to writing:
| ?- Object::Message1; Object::Message2; ... .
To send the same message to a set of objects we can write:
| ?- (Object1, Object2, ...)::Message.
This will have the same semantics as:
| ?- Object1::Message, Object2::Message, ... .
If we want to use backtracking to try the same message over a set of objects we can write:
| ?- (Object1; Object2, ...)::Message.
This will be equivalent to:
| ?- Object1::Message; Object2::Message; ... .
While defining a predicate, we sometimes need to send a message to self, that is, to the same object that has received the original message. This is done in Logtalk through the ::/1
prefix operator:
::Message
We can also use the broadcasting constructs with this operator:
::(Message1, Message2, ...)
or:
::(Message1; Message2; ...)
The message must match a public or protected predicate declared for the receiving object or a Logtalk/Prolog built-in predicate otherwise an error will be thrown (see the Reference Manual for details). If the message is sent from inside a category or if we are using private inheritance, then the message may also match a private predicate.
When redefining a predicate, we sometimes have the need to call the inherited definition in the new code. This possibility, introduced by the Smalltalk language through the super
primitive, is available in Logtalk through the ^^/1
prefix operator:
^^Predicate
Most of the time we will use this operator by instantiating the pattern:
Predicate :- ..., % do something ^^Predicate, % call inherited definition ... . % do something more
Every message sent using ::/2
operator generates two events, one before and one after the message execution. Messages that are sent using the ::/1
(message to self) operator or the ^^/1
super mechanism described above do not generate any events. The rational behind this distinction is that messages to self and super calls are only used indirectly in the definition of methods or to execute aditional messages with the same target object (represented by self). In other words, events are only generated when using an object's public interface. They can not be used to break object encapsulation.
If we need to generate events for a public message sent to self, then we just need to write something like:
Predicate :- ..., self(Self), % get self reference Self::Message, % send a message to self using ::/2 ... .
If we also need the sender of the message to be other than the object containing the predicate definition, we can write:
Predicate :- ..., self(Self), % get self reference {Self::Message}, % send a message to self using ::/2 ... . % sender will be the pseudo-object user
See the session on Event-driven programming for more details.