Go to the first, previous, next, last section, table of contents.


Inheritance

A class can be similar to an already existing class, and it would be a waste to have to rewrite the behaviour already provided by that existing class. The new class can inherit the behaviour, and state, from an already existing class. The new class will then be a subclass of the other class, which will be the superclass of its subclass.

Inheritance is, by definition, public. This implies that any method declared in a superclass is available in exactly the same way to users of the inheriting class, as it is to users of the inherited class. Private inheritance, like it is available in C++, is not available in TOM, as the concept implies a contamination of the `is-a' and `part-of' hierarchies. Anything achievable through private inheritance can also be obtained by adding an instance variable of the proper type instead of privately inheriting that type. An advantage of the private inheritance is the availability of direct access to the inherited class' instance variables and the direct association of the instance part of the inherited class with the whole object of the subclass. On the other hand, the fact that a class can only be (privately) inherited once is only one the reasons private inheritance is considered a bad idea.

Inheritance is not restricted to a single superclass. A class may inherit any number of classes. If two inherited classes share a superclass, the state carried by that superclass will, by definition, appear in the new class exactly once. Thus, repeated inheritance is always shared inheritance.

Method clashes due to inheritance, when two distinct superclasses both implement the same method, must be resolved by the new class providing its own definition of the method, or by the new class indicating which inherited implementation is to be preferred.

[Note: Currently, the tools (compiler and resolver) do not yet provide the latter option. End note.]

If a class declares deferred methods, the class itself is said to be a deferred class. If a class is a direct subclass of a deferred class, and it does not provide an implementation for all inherited deferred methods, either explicitly or through inheritance, the new class is a deferred class too.

Syntax

A class or instance is defined or declared by an appropriate object_def.

object_def:
          ( `implementation' | `interface' )
          ( `instance' | `class' ) class_name [extension]
          [supers] [object_variables] method* `end'
        ;

A class is only fully declared if the interface of both its class and its instance have been seen. A class is fully defined by the implementation of its class and instance. The implementation is what a programmer writes; the interface is usually generated by gi (see section gi).

When compiling TOM code, the compiler reads only the implementation of the classes to be compiled (which, per run of the compiler, all reside in the same file). All other classes it needs to know about are declared by reading the interface files. Before actually compiling an implementation, the corresponding interface is read. Any discrepancy between the interface and the implementation is an error: state declared in the interface must exactly match state in the implementation; similarly, any method defined in the implementation must have been declared in the interface, and vice versa.

The extension, if present indicates that the current interface or implementation does not actually concern the class' main extension, but the extension named in the extension (see section Extensions).

supers:
          `:' super_list
        ;

super_list:
          super_indication [`,' super_list]
        ;

super_indication:
          [`posing'] class_name
        | `instance' `(' class_name `)'
        ;

If the super_indication is a class_name the inheritance applies to both the class and the instance of the object currently being defined or declared. It is customary to indicate this kind of plain inheritance with the class, not the instance. If posing is present, the current class poses the indicated super class.

The inheritance of only an instance (the second case), applies only to the current object (either instance or class) being defined or declared. In this case, the instance being inherited must be a behavioural instance.

object_variables:
          `{' object_variable+ `}'
        ;

The object_variables define the state introduced by a class or instance (or an extension thereof).

object_variable:
          [`local'] [`static'] object_var_qualifier*
          entity_type identifier_list `;'
        ;

An object_variable introduces the variables named in the identifier_list. Every variable has the type denoted by the entity_type.

The static may only be present in the definition of a class. It denotes that the variables introduced are shared between this class and all its subclasses. If omitted, every class will have its own copy of these variables, just like every instance always has its own copy of the instance variables defined for it.

The local qualifier may only be present on a static variable. It denotes that every thread in the running program will have its own value for this variable. An example of its use is the current Thread class variables, which is declared like this:

local static public instance (id) current;
object_var_qualifier:
          `redeclare'
        ;

An object variable can be indicated to be a redeclaration of an object variable inherited from a superclass. Redeclaration is only allowed to indicate that the variable will actually be a reference to an object whose class is a subclass of the class originally being the type of the variable. Thus, changing an object variable's type from, for instance, char to long is not allowed.

method:
          method_declaration
        | method_definition
        ;

A method_declaration is only allowed in an interface; an implementation will only contain method definitions. (Note that some identical expansions of a method are a declaration in the context of an interface a definition in an implementation. The reason for this is that interfaces are generated from implementations, and they must be generatable from something.)


Go to the first, previous, next, last section, table of contents.