CSC/ECE 517 Fall 2012/ch1 1w23 as: Difference between revisions
No edit summary |
|||
Line 11: | Line 11: | ||
==Issues of Multiple Inheritance== | ==Issues of Multiple Inheritance== | ||
1 | 1. Due to inheritance, the parent class’s objects get duplicated to derived class. As a result, Allrounder Class duplicates Cricketer objects through each of Batsman and Bowler classes. When Allrounder accesses any of the Cricketer’s attributes, the compiler would be ambiguous about determining the correct path to use since two paths are available from Allrounder to Cricketer. This problem of multiple inheritance is called diamond problem. Compiler takes arbitrary decisions during such situations. | ||
2.Objects of parent classes can be separately managed using virtual tables as in C++. By explicitly specifying the virtual table pointer, the Allrounder class can access Batsman and Bowler classes unambiguously. However virtual tables occupy significant portion of memory thereby limiting their extensive usage. | 2.Objects of parent classes can be separately managed using virtual tables as in C++. By explicitly specifying the virtual table pointer, the Allrounder class can access Batsman and Bowler classes unambiguously. However virtual tables occupy significant portion of memory thereby limiting their extensive usage. |
Revision as of 02:37, 12 September 2012
1w23: Multiple Inheritance and Mixins
Introduction
Multiple Inheritance
Multiple Inheritance is a technique of establishing hierarchical relationships within a set of classes, such that a single class can inherit behaviors from multiple parent classes. Although it might seem useful, to include methods from multiple classes, the major issue with multiple inheritance is the ambiguity in referencing the parent class methods, when more than one parent classes share a method with the same name.This ambiguity is predominant in cases where the inheritance hierarchy is more than one level deep, where the class in the lowermost level inherits from two classes, that have overridden the same method from their parent in different ways.Now the class in the lowermost level has two different implementations of its grand-parent’s method resulting in an ambiguous situation, which is otherwise called as the Deadly Diamond of Death problem.
A Real World Example
Let us consider an example of representing players of Cricket using classes and objects. The players of Cricket are instances of class Cricketer. Classes Bowler and Batsman inherit Cricketer’s state and behavior. All rounders inherit states and behaviors of Batsman, Bowler and subsequently from the Cricketer through Batsman and Bowler classes. Let us explore the issues of multiple inheritance in reference to this context.
Issues of Multiple Inheritance
1. Due to inheritance, the parent class’s objects get duplicated to derived class. As a result, Allrounder Class duplicates Cricketer objects through each of Batsman and Bowler classes. When Allrounder accesses any of the Cricketer’s attributes, the compiler would be ambiguous about determining the correct path to use since two paths are available from Allrounder to Cricketer. This problem of multiple inheritance is called diamond problem. Compiler takes arbitrary decisions during such situations.
2.Objects of parent classes can be separately managed using virtual tables as in C++. By explicitly specifying the virtual table pointer, the Allrounder class can access Batsman and Bowler classes unambiguously. However virtual tables occupy significant portion of memory thereby limiting their extensive usage.
3. The order by which Allrounder class inherits Batsman and Bowler classes also matters. If Allrounder inherits Batsman prior to Bowler, then Batsman precedes Bowler and common methods are accessed in this order of precedence. Hence if the Programmer is not aware of such precedences, debugging would be difficult.
Solutions
Programming languages provide different solutions to handle the issues of multiple inheritance. Here we consider the techniques offered by C++, Java and Ruby.
Multiple Inheritance in C++
C++ supports multiple inheritance with the notion of virtual classes and functions. In the example, the Cricketer class defines virtual functions with Batsman and Bowler classes virtually inheriting the features of Cricketer. The Allrounder class can now unambiguously access Cricketer class using virtual table pointers of Batsman and Bowler. The example written using C++ virtual functions is shown below.
class Cricketer {
protected: char* country; char* player_type; public: virtual void statistics() { cout<<"Cricketer's statistics include number of matches, average, best performances etc."<<endl; } }
};
class Batsman : virtual public Cricketer {
public: void statistics() { cout<<"Batsman's statistics include batting average, number of 100's & 50's, top score etc."<<endl; } // other methods to operate on Cricketer & Batsman specific attributes
};
class Bowler : virtual public Cricketer {
public: void statistics() { cout<<"Bowler's statistics include number of wickets, bowling average, economy etc."<<endl; } // other methods to operate on Cricketer & Bowler specific attributes
};
class Allrounder: public Batsman, public Bowler {
public: void statistics() { cout<<"Allrounder's statistics include batting average, bowling average etc."<<endl; } // other methods to operate on Cricketer, Batsman & Bowler specific attributes
};
int main() {
int i = 0; Cricketer *instances[3]; Batsman bat; Bowler bowl; Allrounder all; instances[0] = &bat; instances[1] = &bowl; instances[2] = &all; while(i<3) instances[i++]->statistics(); return 0;
}
Multiple Inheritance in Java
Java doesn’t support multiple inheritance but provides a feature called interfaces to resemble inheritance from multiple classes. Interface is an abstract class which provides a generic template by just declaring variables and methods without definition. Concrete classes that inherits interfaces are supposed to implement its methods. The example written using Java interfaces is shown below.
interface Cricketer {
void statistics();
}
interface Batsman extends Cricketer {
void statistics(); // other methods to operate on Cricketer & Batsman specific attributes
}
interface Bowler extends Cricketer {
void statistics(); // other methods to operate on Cricketer & Bowler specific attributes
}
interface Allrounder extends Batsman, Bowler {
// other methods to operate on Cricketer, Batsman & Bowler specific attributes
}
class ImplementBatsman implements Batsman {
public void statistics() { System.out.println("Batsman's statistics include batting average, number of 100's & 50's etc."); } // other methods to operate on Cricketer & Batsman specific attributes
}
class ImplementBowler implements Bowler {
public void statistics() { System.out.println("Bowler's statistics include number of wickets, bowling average, economy etc."); } // other methods to operate on Cricketer & Bowler specific attributes
}
class ImplementAllrounder implements Allrounder {
ImplementBowler bowl = new ImplementBowler(); ImplementBatsman bat = new ImplementBatsman();
public void statistics() { bowl.statistics(); bat.statistics(); } // other methods to operate on Cricketer, Batsman & Bowler specific attributes
} public class MultipleInheritance {
public static void main(String args[]) { ImplementAllrounder all = new ImplementAllrounder(); all.statistics(); }
}
Mixins in Ruby
Ruby doesn’t support multiple inheritance but provides a more similar feature using mixins. The example written using ruby mixins is shown below.
module Cricketer
def statistics puts "Cricketer's statistics include number of matches, average etc." end
end
module Batsman
include Cricketer def statistics puts "Batsman's statistics include batting average, number of 100's & 50's etc." end
end
module Bowler
include Cricketer def statistics puts "Bowler's statistics include number of wickets, bowling average, economy etc." end
end
class AllRounder
include Batsman include Bowler include Cricketer # Other implementation
end all = AllRounder.new() all.statistics()
Multiple inheritance in other languages
Scala offers traits that are similar to Java interfaces to support multiple inheritance. Traits define a template with methods and variables which any class can make use of. The difference between interfaces and traits is that traits can implement methods. A Scala class can inherit from any number of traits together with a class in way to support multiple inheritance. Traits can be mixed in to a class even without inheriting it but just by including it at the time of instantiation The language enforces method names to be different across inherited traits to avoid the issues of multiple inheritance. Python supports a limited version of multiple inheritance by extending multiple classes in depth-first left-right order. If a python class D inherits classes A, B, C and if an instance variable or method is not available in the current class, it checks in A and its base classes, then moves to B and its base classes and eventually to C thus moving from left to right. In this way, python avoids the diamond problem by linearizing the search order by which the derived class accesses attributes of its parent classes. In addition python also defines mixins to access reusable features within a class.
Questions to ponder
Do mixins solve all of these problems?
Undoubtedly mixins solve some of the problems of multiple inheritance. There is no ambiguity in resolving the request to a common method implemented by multiple modules. In that case, the lastly included module is responsible for handling accesses to common methods. Though the order of precedence of included modules matters, it looks clearer than C++. However languages like Scala and Eiffel implement multiple inheritance far more safely by explicitly forcing the user to have different method names across inherited classes.
Are mixins a clear advantage over interfaces?
Mixins are more advantageous than interfaces because of their features. Interface is a concept to simulate multiple inheritance and is not as powerful as C++. As seen from programs, the derived class Allrounder uses the instances of Batsman and Bowler classes (has-a relationship) to access respective attributes. Interface is nice in the sense it provides a generic template that could be implemented differently by different classes. However the target class has to necessarily implement every method of the interface. This would pose problems to a Class which is interested in implementing specific features of the interface. On the contrary, Mixins eliminates this inconvenience by mixing in the state and behavior of the modules in the target class and allows a it to use them as it needs. Hence the target class can just use module’s features selectively or completely instead of implementing by itself. The size of multiple inheritance code using mixins is smaller than interfaces and C++ variants.
Inspite of making the lives of programmers better with effective code reuse and avoiding unnecessary implementation of methods that cause clutter in the code, the concept of Mixins can easily be abused resulting in namespace pollution. This is caused when a class includes multiple modules each of which contains several hundred method implementations. Having hundreds of methods mixed into a single class, makes it difficult to identify the source modules of the methods, thereby causing confusion while implementing these methods, whereas in the case of multiple inheritance we can easily identify the class to which the method belongs. Another disadvantage that follows from the namespace collision is the case where we have multiple methods with the same name in different modules.In such a case whenever a call to that method is made, the method which belongs to the module that was included last will be called. The problem with this is that, this takes place silently without any warning. This may result in accidental overriding of wrong methods.
References
http://www.innovationontherun.com/why-rubys-mixins-gives-rails-an-advantage-over-java-frameworks/
http://www.pxleyes.com/blog/2010/02/pros-and-cons-of-3-popular-css-meta-frameworks/
http://www.artima.com/weblogs/viewpost.jsp?thread=246488
http://www.linuxtopia.org/online_books/programming_books/ruby_tutorial/Ruby_Modules_Mixins.html