8.3. Inheritance

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