Previous Page TOC Next Page



6. Variables

Variables can be declared of any class. This is done in separate variable declaration sections. Such a section exists for the whole class (instance variables) and once for each routine (local variables) and is preceded by the keyword var. The scope for instance variables is the class definition, the scope for local variables is the routine they are declared in.

The section declaring the instance variables must be in the internal section and must precede the internal routine declarations. No variables are allowed in the class interface.

The section declaring local variables follows the preconditions and constant declarations in a routine declaration and precedes the routine statement block.

BNF:

var-decls   ::=   var-decl { var-decl }
var-decl   ::=   ident-list  ":" type-def [ initialisation ]
type-def   ::=   class-ident [ "<" ident-list  ">" ]
class-ident   ::=   identifier 
initialisation   ::=   ":=" expression

Examples:

var

num1, num2: Integer
count : Integer := 0
int_arr: Array <Integer>
f: Figure
s: Stack <Figure> printList (l: List) is
== print all list elements var
cnt: Integer
nm: String := "" do
...
end printList

Lifetime

The lifetime of local variables is the time of a routine execution. In other words: scope and lifetime are connected (as in Pascal). There is no mechanism to extend the lifetime of local variables beyond the procedure execution (such as the "static" construct for local variables in C).

The lifetime of instance variables is the time of existence of the object they are part of.

States and Values

Variables are a combination of type, state and value. The type of a variable is specified statically and never changes. At any time, each variable is in one of two states: undefined or defined. If a variable is defined, it also has a value. The value of a variable is always a reference to an object of its type (or nil, see below).

A variable can be initialised on declaration by any legal expression, using the assignment instruction (see example above). If a variable is not initialised at its declaration, its initial state is undefined. It is an error to use an undefined variable. An attempt to do so results in a runtime error.

No function exists to check for the state undefined. It is the responsibility of the programmer at the time of writing the program to ensure that variables are not used in the undefined state. (A good programmer will always know when a variable is potentially undefined. Parameters can never be undefined - that would have resulted in a runtime error at the time of the call.)

Assignment of a value to a variable changes the state to defined. After a variable leaves the state undefined, it never returns to that state.

Nil

A special value called nil exists. The value nil indicates that the variable does not reference any object. A variable of any type can hold the value nil. nil can be assigned, passed as a parameter and used in comparisons. Trying to use the object held by a nil variable (e.g. in an object call) is an error, since the variable does not refer to an object.

Encapsulation

Variables are encapsulated and cannot appear in the interface of a class. This means that a class cannot directly access a variable of another class. (It can indirectly access it if that class offers a function that returns or changes the value of a variable, but this is the choice of the class owning the variable.)

The only variables directly accessible are local variables of the current routine and instance variables of the current class.

Note, however, that encapsulation is class based, not object based. As a result, a class can access variables in another object, if that object is of the same class.

Example:

class Point is

...
var
x, y: Integer
... add (other : Point) is
== Add another point to this one
do
x := other.x
y := other.y
end add

This technique is useful in situations where access to the internals is needed, and no interface access functions are defined. (An object clone function is such a case where an object might want to create a new object of its own class and set all its instance variables to the same values as itself. We would not want to make all internal variables publicly accessible only to be able to provide a clone function.)

The possibility of accessing instance variables of another object, even though they are of the same class, seems to some people to go against the information hiding (or encapsulation) principle. And in some respects it does. To understand the reason for this access to be allowed, we must understand why information hiding is a good idea in the first place.

Information hiding is a software engineering technique, that decouples the implementation of different modules (here: classes) from each other. Accessing variables directly in arbitrary places is a maintenance d isaster, because changes to the implementation of one module might require changes in unexpected other places in the program. This is why we do not allow direct access of instance variables.

If the access comes from the same class, though, (even if it is from another object) the argument does not hold anymore. If I change the implementation of that class, I will change all accesses to a variable within that class. So allowing access to instance variables of other objects from within the same class is no problem.

Previous Page TOC Next Page