CSC/ECE 517 Fall 2007/wiki1 7 c9

From Expertiza_Wiki
Revision as of 04:15, 14 September 2007 by Smalugu (talk | contribs) (→‎C++ code)
Jump to navigation Jump to search

Concept to explore

Multiple inheritance is a controversial concept. Detractors say it leads to messy class hierarchies, it is impossible to implement efficiently, and when the same method is inherited along two different paths, there is no good way to decide automatically which definition should be used. Do mixins solve all of these problems? Give (or cite) examples (e.g., Java, C++, and/or Ruby) to illustrate your conclusions. Are mixins a clear advance over interfaces? Do mixins have any disadvantages not shared by multiple inheritance or interfaces?

Definitions

Inheritance

The process of having a class derive or inherit functionality of other class is called Inheritance. This concept offers reusabilty of code and also can be used to represent real world relationships . Depending on the number of parent classes , we can classify single and multiple inheritance .Depending on the extent of access of the parent class that the child class has, we have public..protected and private inheritance.


Multiple Inheritance

This is the situation of a child class deriving functionality from multiple ( more than one ) parent classes . For example a Bike needs to derive functionality from both the " Two wheeler " class and "Motor Vehicle" class simultaneously. This could lead to ambiguity in a particular case . When class B and class C are children of class A and a class D inherits from both B and C , then ambiguity arises when D needs to access A's method. Compilers of many object oriented languages usually are unable to determine which version ( the path from B or the path from C) of the method needs to be considered .

This is considered to be the Famous "Deadly diamond of death " or DDD. Different languages have different approaches in dealing with the DDD problem . C++ uses virtual base classes while Java simulates it through the concept of interfaces. Ruby uses Mixins to solve the problem


Interfaces in Java

Interfaces in Java provide the template for the classes implementing it . Each class implementing it needs to provide the implementation of the method which is defined in the Interface.


Modules

Modules provide a way of grouping of objects under a single name . The objects may constants , methods , classes or other modules . Modules provide two benefits : 1. Modules provide a namespace and prevent name clashes . 2. Modules implement the mixin facility ( incorporating module's content into a class)

A module can be thought of a noun like construct as well as an adjective like construct available for modeling . Modules differ from class in that a module cannot be instantiated like a class . However we can 'include' the module within a class definition ( using 'include if module is in same file or 'require if it is in different file) Module usually contains methods called "module methods" whose names are prefixed with the module name .

Mixin

The other usage of modules other than Namespace implementation is the Mixin. Mixin provides a wonderfully controlled way of adding functionality to the classes. A mixin is a module defined to be included into the definition of a class which would like to include its functionality . Unlike Java interfaces , mixin modules can include the implementation of the methods along with their definitions.

One major advantage of mixin is that we can simulate Multiple Inheritance , as Ruby in concept allows only single inheritance in terms of classes deriving from other classes. With the required functionality enclosed in a Mixin , the classes can inherit(misnomer , correct would be include ) from any number of mixins . The problem of the ambiguity of the method choosing typical of a DDD , is solved in Ruby in that the method with the same name that was most recently included would be considered. Mixin generally do not implement instance variable specific to it , but would prefer to derive it from the class object it is associated with .

Real World Problem

Let us see a real world example and see often why some sort of of multiple inheritance is required. Then see in phases how each language C++, Java, Ruby deals this problem.

Consider a part-time student this means that he is both a student as well as an employee(typically). But in first place he is a also person. So, he will have attributes and states of both a student and also of an employee. Since these two classifications first belong to the classification person, part-time student also gets any attributes from the person as well. Lets consider some essential features of a person he eats, he will have fun and also say he has some attribute 'i' to say about his state.
Now, the fun a student will have will be different from an employee, so we should distinguish that and also the state. So we need some sort of specialization. Now the fun a part time student(if any!) might change. This is the crux of the problem all the languages have attempted to solve and each of them have used a different strategy.

In object oriented terms, we can say that part-time student class inherits both from the student as well the employee. Both student and employee inherit from the class person. The person will have methods eat(),fun() and int i (this is represent the state). Student class will derive the state and method fun from person. The same is with employee. Note that here the fun method implementation is different in these classes. And part-time student will get both the derived class fun and the state.


C++ code

// Attempting to polymorphically call a function that is
// multiply inherited from two base classes.
#include <iostream>
using std::cout;
using std::endl;

// class Person definition
class Person
{
public:
virtual void eat() ; // pure virtual
virtual void fun() ; //pure virtual
};


//class Student definition
class Student : public Person
{
public:
// override fun function
void fun ()
{
cout << "Having fun on university campus\n";
}
};

// class Employee definition
class Employee : public Person
{
public:
// override fun function
void fun ()
{
cout << "Having fun on company campus\n";
}
};


// class Part_time_student definition
class Part_time_student : public Employee, public Student
{
public:
// qualify which version of function fun
void print() const
{
Employee::fun();
}
};

int main()
{
Part_time_student both; // instantiate Person object
Employee one; // instantiate Employee object
Student two; // instantiate Student object
Person *array[ 3 ]; // create array of base-class ie Person pointers

array[ 0 ] = &both;
array[ 1 ] = &one;
array[ 2 ] = &two;

// polymorphically invoke fun
for ( int i = 0; i < 3; i++ )
array[ i ] -> fun();

return 0;
}

References:

  1. Programming Ruby: The programmatic programmer’s guide
  2. Deadly diamond of death by Robert Martin
  3. A very insightful article from thoughtbot
  4. Wiki entry on Ruby
  5. The C++ code snipped has been adapted from this site


See Also

  1. A very insightful article from O'reilly
  2. One more blog on mixins, modules and inheritence