Messages that do something more than fetch or store slot values are usually defined as send messages. While the choice of message operators is (usually) up to the programmer, choosing them carefully enhances the readability of a program.
For example, print methods might be defined for the point and rational number classes, respectively, as
Self <- print(Stream) :- Self >> x(X), Self >> y(Y), format(Stream, "(~w,~w)", [X, Y]).
Self <- print(Stream) :- fetch_slot(num, N), fetch_slot(denom, D), format(Stream, "~w/~w", [N, D]).
These methods are used to access slot values. But, the fact that the values are printed to an output stream makes it more reasonable to define them as send messages than get messages.
Frequently send methods modify slot values. For example, the point class might have methods that flip points around the x and y axes, respectively:
Self <- flip_x :- Self >> y(Y0), Y1 is -1 * Y0, Self << y(Y1). Self <- flip_y :- Self >> x(X0), X1 is -1 * X0, Self << x(X1).
And, the rational number class might have a method that swaps the numerator and denominator of a rational number object. It fails if the numerator is 0.
Self <- invert :- fetch_slot(num, N) N =\= 0, fetch_slot(denom, D) store_slot(num, D), store_slot(denom, N).
These methods modify slot values, but they do not simply store values that are given in the message. Hence, it is more reasonable to use the send operator.
It is possible for a method to produce more than one answer. For example, the class whose definition begins with
:- class interval = [public lower:integer, public upper:integer].
might define a send method
Self <- in_interval(X) :- Self >> lower(L), Self >> upper(U), between(L, U, X).
which uses the
between/3 predicate from
in_interval message will bind
X to each integer, one at a time,
between the lower and upper slots, inclusive. It fails if asked for
too many answers.
The rest of this section describes particular kinds of send messages.