t3x.org / t3x / t3x-manual / 295.html
 
T3X - A Minimum Procedural Language
Version 8.1.5, Online Edition
Copyright(C) 1996-2004
Nils M Holm
 
Previous:
2.9.4 Modules and Class Dependencies
TOC | Index | Back Next:
2.9.6 Class Constants

2.9.5 Methods and Messages

Messages are used to alter the state of an object from the outside. Basically, procedural programs are sets of procedures calling each other. An object oriented program is a set of objects sending messages to each other. Sending a message to an object activates a public procedure defined in the class of the object. A method definition looks like a procedure definition with the keyword PUBLIC attached:

PUBLIC procname(arguments) statement

Method definitions are only valid in class-level scopes. A message is sent to an object using the syntax

objectname.methodname(arguments)

Messages may be factors of expressions or standalone statements. When used as statements, they must be terminated with a semicolon:

objectname.methodname(arguments);

The arguments of a method are passed in the same way as the arguments of a procedure and like a procedure, a method returns a value. The difference between an 'ordinary' procedure and a method is that a method changes the instance context upon entry. An instance context is a set of data objects defined in a class. It is comparable to local contexts of procedures: when a procedure is entered, it creates a new local scope and when it leaves, it restores the caller's context. Unlike a local scope, though, the instance context is persistent. Therefore, methods do not create a new instance context, but just activate an existing context. The caller's context is saved upon entry (usually on the runtime stack) and restored when the method returns. Since instance contexts are persistent, changes to instance variables performed by methods are permanent.

Each object has its own instance context, which is divided into the data objects declared in its class. Methods use the instance context to access class-level data. By shifting the instance context upon entry, each object accesses only its own private data. The instance context may be thought of as a multiplexer. The principle is illustrated in the following figure:

+------------+
|  Class A   |
|------------|             +----------------+
|  Method m  | ----------> |   Access V     |
|    ...     |             +----------------+
| Variable V |                      |
+------------+                      |
                                    V
                         +--------------------+
                         |  Instance Context  |
                         +--------------------+
                                |      |
                                |      |
                       ,--------'      '--------,
                       |                        |
                       V                        V
               +---------------+         +---------------+
               |   V of x[A]   |         |   V of z[A]   |
               +---------------+         +---------------+
               |  Object x[A]  |         |  Object z[A]  |
               +---------------+         +---------------+
Fig.3 Multiplexing Method Applications

In this figure, class A defines a method m which accesses the instance variable V which is also declared in A. The instance of V accessed by m depends on the object the message is sent to. Sending x.m(), for example, results in accessing the V of x and sending z.m() results in accessing the V of z.

In T3X, the current instance (the currently active instance context) can be referred to using the symbol SELF. SELF is a pseudo-variable which always refers the the object owning the current instance context. Therefore, SELF may only be used inside of procedures local to classes. Using SELF, an object may send a message to itself, as shown in the next example

CLASS math()
 PUBLIC prod(i, j) DO VAR p;
        p := 1;
        FOR (i=i, j+1) p := p*i;
        RETURN p;
 END

 PUBLIC fac(n) RETURN self.prod(1, n);
END

In this example, the method fac of the class math uses the method prod of the same class to express the factorial of n by sending the message prod(1,n) to itself. Of course, methods may recurse, too, since they are basically procedures. Therefore, fac could as well be defined this way:

PUBLIC fac(n) RETURN n=1-> 1: self.fac(n-1) * n;

Since objects are basically vectors, they may be passed to procedures (or methods) as parameters. By passing an object to a procedure, however, the object loses its type information, since the pointer to the object is stored in a typeless argument variable by the callee. To be able to send messages to such objects, the SEND operator is introduced. Its gerenal form is

SEND(variable, classname, methodname(arguments))

This operator sends the message methodname(arguments) to the object of the class classname pointed to by variable. For example, the statement

y := m.fac(5);

is equal to

pm := @m;
y := SEND(pm, math, fac(5));
Previous:
2.9.4 Modules and Class Dependencies
TOC | Index | Back Next:
2.9.6 Class Constants