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();
...