Features
Classes can be defined by extending an already defined class. Inheriting fields and methods follows the "usual" Object-Oriented semantics. Basic features of inheritance: * There is no support for multiple inheritance. * the extended class inherits all the fields of the base class * the extended class inherits all the methods of the base class * all methods are virtual, and they can be overridden in subclasses with methods with same name/arity
Syntax
Defining a class with superclass
When a class is extended, its definitions are required, similarly to the case when the class is used:
-include("animal.class.hrl").
Let us define a subclass of animal
and name it giraffe
:
-include("animal.class.hrl").
-class(giraffe).
?SUPERCLASS(aninal).
The ?SUPERCLASS
macro specifies the superclass of the current class. An ECT class can only have at most one of it. It is defined in ect.hrl
as all the macros of ECT. Despite this, you can note in the current case that ect.hrl
is not included. This is because all the *.class.hrl
files implicitly include them.
Defining fields and methods
The syntax of defining fields and methods of a class is the same as in the case without superclass, but inheritance may alter the effects in this case.
?FIELDS({height = 5, giraffe_id}).
?METHODS([method2/2, method3/2]).
The resulting class will have all the fields of its superclasses and also the locally defined fields. Field names defined in superclasses must not be repeated. The resulting class will also have all the methods defined in superclasses and the ones defined locally. If a locally defined method has the same name/arity as one defined in superclasses, then it overrides it.
Using inherited classes
Field handling
When working with an instance of an inherited class, field handling provides some extra features compared to record field handling. The syntax is the same, but an object can be accessed using either the name of its class, or the name of any of its superclasses. Record-syntax only allows the use of the name of the exact class. If we take the following object:
A = #giraffe{color = yellow, giraffe_id = g123},
then following expresions are valid both with records and ECT objects:
```
X1 = A#giraffe.weight,
giraffe{color = red, height = 5} = A,
A2 = A#giraffe{color = green, giraffe_id = g506}
but the following is not valid with record syntax, only with ECT objects:
X1 = A#animal.color,
animal{color = red, weight = 15} = A,
A2 = A#animal{color = brown, weight = 25}
```
In other words, ECT makes it possible to handle an object as if it had one its superclasses. Note that in the second code block, height
and giraffe_id
of giraffe
are not accessed. Actually, this block will work correctly in any case, if A
is an object of class animal
or any of its subclasses.
Method calls
The following method calls:
{A}:method1(1),
{A}:method2(1),
{A}:method3(1).
are interpreted the following way:
animal:method1(A, 1),
giraffe:method2(A, 1),
giraffe:method3(A, 1)
if we assume that A
is a class of giraffe
as defined in the previous section.
* method1/2
is only defined in animal
* method2/2
is defined in animal
but its definition in giraffe
overrides this
* method3/2
is only defined in giraffe
The module names are always determined at run time. The overhead of this is in O(1).
You can read more on method calls, here: Methods.
Complete class source code
``` -include("animal.class.hrl"). -class(giraffe). ?SUPERCLASS(animal).
?FIELDS({height = 5, giraffe_id}). ?METHODS([method2/2, method3/2]).
method2(This, A) -> A+2. method3(This, A) -> A+3. ```