4.3. Attribute definitions

Example 4-3. Examples:

attr a,b,c:INT;
private attr c:CHAR;
readonly attr s1,s2:STR
attr_definition ==>
        [ private  | readonly ] attr identifier_list : type_specifier

An object's state consists of the attributes defined in its class together with an optional array portion. The array portion appears if there is an include path (See Code inclusion and include clauses) from the type to AREF for reference types or to AVAL for immutable types (See Built-in classes). Closure and reference objects must be explicitly allocated as described on pages See new expressions and See Closure creation expressions. Variables have the value 'void' until an object is assigned to them (See void expressions). There must be no cycle of immutable types such that each type has an attribute whose type is in the cycle.

Each attribute definition causes the definition of a reader and a writer routine with the same name. The reader routine takes no arguments and returns the value of the attribute. Its declared return type is the attribute's type. It is private if the attribute is declared 'private'.

The writer routine takes different forms for reference and immutable types. For reference types, the writer routine takes a single argument whose type is the attribute's type and has no return value. Its effect is to modify the object by setting the value of the attribute. For immutable types, it takes a single argument whose type is the attribute's type, and returns a copy of the object with the attribute set to the specified new value, and whose type is the type of the object. Object attribute writer routines are private if the corresponding attribute is declared either 'private' or 'readonly'.

4.3.1. Attribute, shared and constant examples

Example 4-4. Here's an example of a tree node class. Each node has attributes for storing child nodes as well as the data at that node. 'datum' and 'total_nodes_created' are marked readonly, so they may not be written by code in other classes. The 'total_nodes_created' field is presumably incremented in the create routine, and all nodes will see the same value.

The 'lchild' attribute implicitly defines two signatures: 'lchild:NODE{T}' for reading and 'lchild(NODE{T})' for writing.

class NODE{T} is

   attr lchild, rchild:SAME;
   readonly attr datum:T;

   readonly shared
      total_nodes_created:INT;

   const min_balanced_depth:INT:=5;

   ...
end

Example 4-5. This example shows three different ways to modify an attribute. 'n' is a reference type, so the 'lchild' field can be modified by assignment, or by calling the implicit writer routine for the attribute. 'c' is an immutable type, so its implicit writer routine returns a new object instead of modifying the object in place.

n:NODE{T};
c:CPX;
...
n.lchild := x;  -- These two lines
n.lchild(x);    -- are equivalent.
...
c := c.re(1.0); -- attr of immutable type