Let us consider the following example where a new class is created:
class Book Catalog
{
size = 0;
}
The Book class is called a
derived class and the Catalog
class is called a base, or parent
class for the Book class. In addition to having its own
attributes, methods, and class variables, a derived class
inherits all these things from the base class as
well. For example, the Book class inherits the
data attribute from the Catalog
class:
(defclass Book Catalog [][data (size . 0)])
The relation between the base classes and the derived classes can be described as an "is-a" relation: a derived class "is-a" base class, with its own additional features. Due to inheritance, an instance of a derived class in Gamma can call any method of the base class just like it was an instance of the base class itself:
Gamma>math = new(Book);{Book (data) (size . 0)}Gamma>math.Lookup("Calculus");nil
In this case it returns nil
because no entry "Calculus" was added to the list of data. Now we can create an
Add method for the Book class.
This method adds an author and a publisher to the association list of data. If
the Add operation is successful, the size of the list is
incremented by 1. This Add method internally calls the Add
method of the base Catalog class using the call function. We say that the
derived class inherits implementation from the base class. If we were to change
the way the Add method is implemented in the base class,
the implementation would propagate to the derived class.
method Book.Add (title, author, publisher)
{
local pair = list(author, publisher);
local result = call(self, Catalog, Add, title, pair);
if (result)
{
.size+= 1;
}
}
The method Add can be evaluated as follows:
Gamma>math.Add ("Calculus", "Thompson", "Wiley");1
It returns the size of the math catalog as the result of the last evaluated
expression within the method. Now if we would like to search for the entry
"Calculus", the method Lookup is evaluated as follows:
Gamma>math.Lookup ("Calculus");(Calculus (Thompson Wiley))
Classes can be related by "is-a" relations, since one class is a derived class of the other. There can also be "has-a" relations between classes. Let us consider the following example:
class Figure
{
color;
height;
width;
}
class Book_1
{
size;
figure = new(Figure);
}
Class Book_1 "has" an instance of class Figure as an attribute. In other words, class Book_1 contains one instance of the class Figure. Let us consider the connections between the methods of the two classes with the "has-a" relations. Suppose the following methods are defined:
method Figure.Show()
{
...
}
method Book_1.Show()
{
.figure.Show();
}
The method Show of the Book_1 class
internally calls the method Show of the
Figure ("contained") class. We say that the
Book_1 class delegates its
method to the Figure class. Thus, the effect of the
delegation is implementation inheritance. It's true that to inherit
implementation, the Figure class could be simply derived
from the Book_1 class and the "is-a" relations would be
in effect. But then it would be impossible for an instance of the
Book_1 class to have several instances of the Figure
class.
Note that in the definition of the Book_1 class, the
Figure class is instantiated, which makes the
attribute figure an instance of the
class Figure. Thus, if an instance of the
Book_1 class is created it can evaluate its
Show method right away:
... mystery = new(Book_1); mystery.Show(); ...
However, if
an instance of figure is not actually created in a
Book class definition,
class Book_2
{
size;
figure;
}
method Book_2.Show()
{
.figure.Show();
}
then it has to be instantiated for each new instance of
Book_2 before any "delegation" will occur:
... mystery = new(Book_2); mystery.figure = new(Figure); mystery.Show(); ...