Sather has special support for classes that define immutable objects. Such objects cannot be modified after they have been created, and are said to have value semantics. Many of the basic types such as integers and floating point numbers (the INT and FLT classes) are implemented using immutable classes. This chapter illustrates how immutable classes may be defined, and highlights the peculiarities in their usage that may trip up a beginning user.
At a fundamental level: immutable classes define objects which, once created, never change their value. A variable of an immutable type may only be changed by re-assigning to that variable. When we wish to only modify some portion of an immutable class, we are compelled to reassign the whole object. For experienced C programmers the difference between immutable and reference classes is similar to the difference between structs (immutable types) and pointers to structs (reference types). Because of that difference, reference objects can be referred to from more than one variable (aliased), while immutable objects cannot.
This section illustrates the definition of immutable types using a simple version of the complex number class, CPX. We also describe the benefits of immutable classes and when they should be used. Finally, we close with a description of a how to transparently replace in immutable class by a standard reference class which implements value semantics.
In most ways, defining and using immutable classes is similar to defining and using reference classes. Immutable classes consist of a collection of attributes and functions that can operate on the attributes. Since we have already described reference classes in considerable detail, we will describe immutable classes in terms of their differences from reference classes.
We illustrate the use of immutable classes through the example of the complex class CPX. The version shown here is a much simplified version of the library class. The key point to note is the manner in which attribute values are set in the create routine.
immutable class CPX is readonly attr real,imag:FLT; create(re,im:FLT):SAME is -- Returns a complex number with real and imaginary parts set res:SAME; res := res.real(re); res := res.im(im); return res; end; plus(c:SAME):SAME is -- Return a complex number, the sum of 'self' and c'. return #SAME(real+c.real,imag+c.imag); end; end; -- immutable class CPX |
The complex class may then be used in the following manner.
b:CPX := #(2.0,3.0); d:CPX := #(4.0,5.0); c:CPX := b+d; |
Unlike reference classes, instances of an immutable class are not explicitly allocated using the 'new' expression. A variable of an immutable class always has a value associated with it, from the point of declaration. In the example above, the return variable of the create routine ,'res' simply has to be declared.
The initial value of an immutable object is defined to have all its fields set to the 'void' value and this is defined to be the 'void' value of the immutable object. Note that this 'void' value means something different than it does for a reference class. It does not mean that the object does not exist, but rather that all its fields have the 'void' value.
Class Initial Value ------------------------ INT 0 CHAR '\0' FLT 0.0 FLTD 0.0d BOOL false |
The initial values for the built-in immutable classes are defined above. These values will return true for the 'void' test.
Since an immutable object cannot change its value, what does assigning to an attribute mean? Sather's immutable classes define attribute assignment to create a copy of the original object, with the attribute modified. Thus the attribute declaration 'attr re:FLT ' of the CPX class has an implicit attribute setting routine with the signature:
re(new_re_part:FLT):SAME; |
which returns a copy of the original CPX object in which the attribute 're' has the new value 'new_re_value'. Contrast this with a reference class, in which the setting routine would have the signature
re(new_re_part:FLT); |
The syntax of the setting routines of immutable classes is a common source of confusion.
There must be no cycle of immutable types such that each type has an attribute whose type is in the cycle. In the following example, the class PAIR has a FIRST_PART that contains a PAIR - leading to an infinite loop and an infinite size structure.
immutable class PAIR is attr first:FIRST_PART; attr second:SECOND_PART; ... immutable class FIRST_PART is attr begin:PAIR; ... |
Accessing an attribute of a void immutable object will always work. Accessing an attribute of a void reference object results in a fatal error
The 'void' value for the basic classes are useful values - false is the 'void' value for the BOOL class, and 0 for the number classes.