37.3 Self, Message Sending, and Message Delegation

In SICStus Objects, each method is executed in the context of an object. This object may not be the static object where the method is declared. The current contextual object is used to determine dynamically which attributes are accessed, and which methods are called. This leads to a mechanism known as dynamic binding. This object can be retrieved using the universal method self(S), where S will be bound to the current contextual object.

When a message is sent to an object, the corresponding method will be executed in the context of the target object. A message delegated to an object will invoke a method that is executed in the context of the message-delegation operation.

object :: message
:: message
Message sending. Sends message to object, setting Self of the recipient to the recipient, i.e. object. If object is omitted, the recipient is the object in which the goal textually appears.
object <: message
<: message
Message delegation. Sends message to object, setting Self of the recipient to Self of the sender. If object is omitted, the recipient is the object in which the goal textually appears. Delegation preserves Self.

The following objects physical_object, a, and b are written using the default notations for sending and delegation, hiding the contextual variable Self:

     physical_object :: {
             volume(50) &
             density(100) &
             weight(X) :-
                     volume(V),
                     density(D),
                     :(X is V*D)
             }.
     
     a :: {
             volume(5) &
             density(10) &
     
             Method :-
                     physical_object <: Method
             }.
     
     b :: {
             volume(5) &
             density(10) &
     
             Method :-
                     physical_object :: Method
             }.

Notice that the difference between the objects a and b is that a delegates any message except volume(_) and density(_) to physical_object while b sends the message to physical_object. We may now ask

     | ?- a :: weight(X), b :: weight(Y).
     
     X = 50
     Y = 5000

To get hold of the current contextual object, the universal method self(S) is provided. Another way to send a message to Self is to use the constant self. So the following two alternative definition of physical_object are equivalent to the previous one:

     physical_object :: {
             volume(50) &
             density(100) &
             weight(X) :-
                     self(S),
                     S::volume(V),
                     S::density(D),
                     :(X is V*D)
             }.
     
     physical_object :: {
             volume(50) &
             density(100) &
             weight(X) :-
                     self::volume(V),
                     self::density(D),
                     :(X is V*D)
             }.