Implementation inheritance

From Wikipedia, the free encyclopedia

Implementation Inheritance (II) is a form of inheritance in object-oriented languages.

It allows children (the derived classes) of the same parent (the base class) to share code implemented in the parent. Methods, variables, properties, events and other actual code elements are implemented in the parent and used by the children.

A common use of implementation inheritance is when the child uses a method that exists in the parent. In this case the parent will do the work (perform some function) when called upon by the child (i.e. controlled by the child). Any other child that inherits from that parent can re-use the same method.

Implementation Inheritance (II) is often contrasted with Virtual Inheritance (VI). Implementation and virtual inheritance phenomena are fundamental to all object-oriented programming languages.

Contents

[edit] General

Centric to implementation inheritance phenomena is the concept of an 'actual code element' which is contrasted with an 'virtual code element'. For example, in C++ a parent can define a Current_state enumerated variable that can be shared by several children during their operations. Each child can set the variable and allow all other children to be aware of the change in the Current_state of the computing process.

From a software design point of view this code-reuse allows common functionality in the codebase to migrate (gravitate) to base classes where it can be shared along the lines of inheritance from the parents. The result is a 'functional aggregation' of common code to the parents.

Inheritance scope determines the extent of the lines of inheritance between children and parents. Multiple Implementation Inheritance (MII) allows children to inherit actual code elements from 'multiple' parents. MII provides a language mechanism for removing replicated code in the children via the process of Functional Normalization. By using MII any replicated functionality, among the children, is aggregated to the parents (functional aggregation), and then shared along the lines of inheritance between parents and children (ancestor/descendent).

Actual code elements have a use context that defines who can use the code element. The use context is the valid semantic domain 'of use' for any given code element. Single and multiple implementation inheritance are the most fundamental mechanisms that determine the use context of inherited actual code elements.

Other language features effect the element use context. For example, in C++ the keywords public, protected, and private restrict the use context of the code element to client (everyone), children (subclasses) and immediate (only accessible within the class in which they are declared). In C# the static keyword will restrict the use context of actual code elements (class members) to static methods and share the code element with all instances of the class.

Differences in the inheritance scope of actual code elements are the primary language feature that leads to different forms of implementation inheritance. These forms of inheritance have a major impact on the functional normalization of an object-oriented code base.

[edit] Specification Vs. Implementation

Implementation Inheritance (II) is an aspect of class inheritance and is generally contrasted to Virtual Inheritance (VI).

In Implementation Inheritance an inherited child method inherits the FULL IMPLEMENTATION of the method defined in the parent. Thus the child can USE the FUNCTIONALITY defined in the parent. As such the parent SHARES an IMPLEMENTATION of the functionality with every child. This 'sharing' leads to code reuse within the 'functional structure' (inheritance graph) of the class hierarchy created by class inheritance.

Virtual Inheritance, on the other hand, FORCES an IMPLEMENTATION requirement on the child. This leads to the ability of the parent to delegate functionality to the child. The different functionality in different children can then be controlled by the parent in an identical manner

[edit] Actual Code Elements

In Implementation Inheritance (II) a child inherits the implementation for one or more code elements. A code element may be a method, a variable or a property depending on the specific language features of an object-oriented language. Because the code element has an implementation it is called an 'implementation code element' to designate its full implementation aspect.

Implementation code elements (implementation via inheritance) are centric to the concept of implementation inheritance. They always provide an implementation to the derived class (child class). Virtual Inheritance (VI), on the other hand, always forces an implementation in derived classes.

It is important to note that any object-oriented inheritance phenomena can be classified under Implementation Inheritance (II) or Virtual Inheritance (VI) via this articulation. Actual code elements always have an implementation when specified. Virtual code elements, on the other hand, never have an implementation when specified.

[edit] Use Context

Under construction.

[edit] Single (SII) Vs. Multiple Implementation Inheritance (MII)

Single Implementation Inheritance (SII) refers to a feature of object-oriented programming languages in which a class can inherit behaviors and features from ONLY ONE parent. In this case common code in the children can be migrated and shared to only one parent (functional stratification WITH NO FUNCTIONAL ORTHOGONALITY). If the common code is orthogonal (see below) the resulting 'inheritance LINE' allows ONLY 'functional stratification' (layers of inheritance) of the computing functionality

Multiple Implementation Inheritance (MII), on the other hand, refers to a feature of object-oriented programming languages in which a class can inherit behaviors and features from MORE THAN ONE parent. In this case common code can be migrated, along functionally orthogonal lines, to many parents (functional stratification WITH FUNCTIONAL ORTHOGONALITY). If the common code is functionally orthogonal (see below) the resulting 'inheritance TREE' allows BOTH 'orthogonal partitioning' (within a single layer of inheritance) AND 'functional stratification' (layers of inheritance) of computing functionality.

With Single Implementation Inheritance there is no inheritance mechanism to separate the common functionally in a child into separate 'functionally orthogonal' parents.

[edit] Ambiguity

Section in progress

[edit] Resolution

Section in progress

[edit] Default Virtual Methods

Implementation Inheritance (II) is defined as sharing code within a class hierarchy via the lines of inheritance between parents and their children (ancestors and descendents).

It is important to note that language specific SYNTACTIC EXPRESSIONS of Virtual Inheritance (VI) (in SOME languages) makes use of Implementation Inheritance when the SPECIFIC LANGUAGE SYNTAX provides a 'default implementation' of a code element (in the output of the language compiler).

A case in point is when a parent defines a Default Virtual Method. A child then has an option to use the 'default method' OR it can implement its own version of the method (which must have the same method signature.

Default Virtual Methods can be initially confusing when first encountered because they exist in the context of Virtual Inheritance while providing shared functionality (from parent to child) via Implementation Inheritance.

It is important to note, therefore, that Default Virtual Methods are the point where Implementation Inheritance overlaps Virtual Inheritance. As such Default Virtual Methods provide flexibility in software design articulated by the 'option' the child can exercise in implementing a virtual method.

Note that a child can elect to implement a virtual method and still call the default virtual method of the parent (within the body of its version of the virtual method). In this case Implementation Inheritance is used in conjunction with Virtual Inheritance to implement the virtual method of the child.

[edit] Default Virtual Method Implementation

In some languages a parent can optionally provide a default implementation of a virtual method. The child, in turn, can provide its implementation of the virtual method. Default virtual methods are a form of implementation inheritance where the parent implemenation is shared (usable by) the children.

The parent and child implementations can coexist. In a polymorphic design some children may decide to implement their own version of the virtual method and use only that version. Other children may elect not to provide an implementation and use the default version provided by the parent.

Default versions of other code elements (beside methods) demonstrate the complementary nature of between Implementation Inheritance (II) and Virtual Inheritance (GVI)

Note the distinction between a virtual method (which can sometimes provide a default implementation) and an abstract method (which can never provide a default implementation). This, however, does not detract from the semantic meaning of Virtual Inheritance (GVI) which is the ability of the parent to control a child implementation (child code element).

Note that in cases where a default implementation is provided by the parent the current casting context will determine which implementation (child or parent implementation) is used.

[edit] Orthogonal Functionality

When functionality is naturally independent it is said to be 'orthogonal functionality'.

For example, three main areas of common computing functionality are presentation, messaging and storage.

Each of these functional areas are orthogonal in their natures. Storage, for example, can take place without presentation or messaging. Each functional area is considered independent and self sufficient. Each is also considered a 'platform' to be used in the composition of a software application. Each is commonly stratified into more than one layer.

In general the implementation of orthogonal functionality should be grouped along orthogonal lines. This design intention is the key impetus for Multiple Implementation Inheritance.

[edit] Functional Delegation Vs. Functional Aggregation

Implementation Inheritance (II) has functional aggregation, distribution and code re-use aspects to its semantics.

In the context of software design, Implementation Inheritance (II) is a 'functional aggregation' mechanism (Vs. [[Aggregation_(object-oriented programming)|Object Aggregation - referential containment]]) that allows children to use functionality implemented (aggregated) IN the parent.

Implementation Inheritance (II) 'aggregates' functionality to a single location (the IMPLEMENTATION in the parent) and 'distributes' that functionality along the (parent/child) lines of inheritance.

Virtual Inheritance, on the other hand, is a control mechanism for parents that allows 'functional delegation' via an implementation IN the child.

Within the context of class inheritance, functional aggregation and functional delegation SPECIFY where the IMPLEMENTATION of the functionality will reside. FUNCTIONAL DELEGATION specifies that POLYMORPHIC functionality will reside among the children. FUNCTIONAL AGGREGATION specifies that COMMON functionality, needed by the children, will reside in the parents.

[edit] Object-Oriented Functional Normalization

In languages that support Multiple Inheritance of Implementation (MII) the functional aggregation of replicated code (code migration to parents) is called 'Functional Normalization'. Functional normalization simplifies the codebase by removing needlessly replicated code and centralizing functionality into one location. This functionality is then made accessible (distributed) via the lines of inheritance.

Thus Functional Normalization is the process of factoring out replicated code. In this process common code 'migrates' TO the base classes (Vs. migration TO the derived classes).

In object-oriented languages Functional Normalization is not possible without Multiple Inheritance of Implementation. This is because the functional structure of encapsulation, formed by inheritance in the class hierarchy, can only distribute its encapsulated functionality via inheritance (which is a definitive aspect of object oriented languages).

When functionality migrates along orthogonal lines (different parents) only Multiple Inheritance of Implementation can bring that functionality back to the child as an inherited function. Since 'COMMON CODE MIGRATION' is ultimately 'ORTHOGONAL' in its nature (there is no Single-Super-Class that does everything), orthogonal functional migration REQUIRES multiple parents.

Single inheritance (SI), on the other hand, can only inherit from one parent. Non-orthogonal normalization is possible (migration of common code from child to parent) but only to a single parent. Orthogonal Functional Migration of common code (in a large code base) to many orthogonal parents is not possible with single inheritance as there is NO (object-oriented inheritance specific) Normalization Mechanism.

Thus Multiple Implementation Inheritance is the normalization mechanism in object-oriented languages.

[edit] Languages

[edit] C++

Section in progress.

[edit] C++ Method Override Ambiguity (MOA)

C++ uses the 'virtual' keyword for method overriding. Method Override Ambiguity (MOA) is an Implementation Inheritance (II) phenomena whereby the implementation of a base class method is 'overridden' in a derived class.

The use of the 'virtual' keyword should not be confused with Virtual Inheritance (VI). The Human Impersonator example code shows that the C++ virtual keyword does not imply the existence of virtual code elements. MOA is a Resolution Inheritance (RI) phenomena whereby a choice between a fixed object and a castable object is made.

The C++ virtual keyword resolves the casting behavior (fixed/castable) of the derived object in the example below.

  // Human Impersonator example
  //
  class Human
     {
  public:
     virtual void  Eye_color() { printf("Eye color is : Blue\n"); }
     };
  class Mutant : public Human
     {
  public:
     virtual void  Eye_color() { printf("Eye color is : Yellow\n"); }
     };
  void Main()
     {
     Human  human;
     Mutant mutant;
     //
     Human  * human_impersonator_ptr;
     //
     human_impersonator_ptr  =   & mutant;
     //
     mutant.  Eye_color();
     human.   Eye_color();
     //
     human_impersonator_ptr  ->  Eye_color();
     }
  // Test driver (main) output
  //
  // WITH     -  'virtual' keyword for Human/Mutant:Eye_color() - Output is 'fixed'
  //
  // Eye color is : Yellow
  // Eye color is : Blue
  // Eye color is : Yellow
  //
  // WITHOUT  -  'virtual' keyword for Human/Mutant:Eye_color() - Output is 'Castable'
  //
  // Eye color is : Yellow
  // Eye color is : Blue
  // Eye color is : Blue
  //

In the Human Mutant example above there are no virtual code elements defined as a code element specification via inheritance. All code elements (Eye_color() method in this case) have implementations.

Method Override Ambiguity (MOA) is a phenomena that results from Implementation Inheritance (II) and not from Virtual Inheritance (VI). It is important to remember this even though C++ uses the 'virtual' keyword as the syntax mechanism of Resolution Inheritance (RI) to resolve the ambiguity.

[edit] C++ Inherited Class Ambiguity (ICA)

C++ uses the 'virtual' keyword for state space collision resolution. Inherited Class Ambiguity (ICA) is an Implementation Inheritance (II) phenomena whereby a child class can inherit (potentially) two instances of the same ancestor class. To resolve the ambiguity of which instance to use C++ provides the virtual keyword that tags a class as having only one 'version' (instance) in the binary code.

The use of the 'virtual' keyword should not be confused with Virtual Inheritance (VI). The example code shows that the C++ virtual keyword does not imply the existence of virtual code elements. ICA is a Resolution Inheritance (RI) phenomena whereby a class that is inherited multiple times has a specific implementation of the state space.

In C++ only one form of state space implementation is available. A class that is multiply inherited will not compile without a 'virtual' keyword designation. Once a class is inherited with the virtual keyword then multiple inheritance of that class is possible (without compiler errors).

The derived class, where the multiple copies 'collide', will have only one copy of the state space of the multiply inherited base class. Other forms of Resolution Inheritance (RI - state space implementation in this case) could allow a separate copy of the base class for each child in the inheritance path. The important point to remember is that the state space collision is resolved with a specific state space implementation. Again, in C++, its a single copy of the state space.

In C++ you specify a class can be multiply inherited via the virtual keyword. The compiler will produce a compile error if it detects a Resolution Inheritance (RI) situation that has an Ambiguity problem.

For example:

//  Bat animal example
class Animal {
public:
      void Eat();
};
// Use RI to inherit Animal (resolve ICA) via 'virtual' keyword
class Mammal : public virtual Animal {
public:
      int  GetHairColor();
};
// Use RI to inherit Animal (resolve ICA) via 'virtual' keyword
class WingedAnimal : public virtual Animal {
public:
      void Flap();
};
// RI ensures only one instance of Animal will be instantiated  (no ICA problem)
class Bat : public Mammal, public WingedAnimal {};
// If RI is not used (via virtual keyword) a compiler error results
void main()
{
  Animal*        animal_ptr;
  Mammal         my_mammal;
  WingedAnimal   my_wingedAnimal;
  Bat            my_bat;
  //
  animal_ptr     =  &  my_mammal;
  animal_ptr     =  &  my_wingedAnimal;
  animal_ptr     =  &  my_bat;           // 'Ambiguous Conversion' (ICA) compile error if no RI
}

Compile Error : In the above, if Mammal and WingedAnimal did not inherit Animal virtually, then the address of my_bat could not be assigned to animal_ptr because of Inherited Class Ambiguity (ICA). If you remove the virtual keyword in the code above you get the compile error.

Resolution Inheritance : In this case Resolution Inheritance (RI) solves the 'Inherited Class Ambiguity' (ICA) POTENTIAL problem by 'forcing' a single copy of Animal (a single instance of the state space) to exist in the binary code. The virtual keyword RESOLVES the potential ambiguity (ICA) over which ancestor CLASS instances to use.

Ambiguity Problem : Inherited Class Ambiguity is a POTENTIAL problem because, in modern C++ compilers, you get a compile time error. An ACTUAL problem of ICA in the runtime binary code (instance of the ICA problem via two instances of Animal in the binary) is impossible.

[edit] C++ Resolution Mechanism for Diamond Problem

In the context of C++ and the Diamond problem the term 'Resolution Inheritance' (RI) is used to distinguish conceptual resolution semantics (see ICA above) from the conceptual control semantics of Virtual Inhertitance (GVI).

In this context (C++/Diamond) the C++ 'virtual' keyword (a syntax mechanism) has a resolution aspect (semantic aspect) to its 'semantic mechanism' (C++ language specification relevant to ICA). Put in simpler terms the 'virtual' keyword (in ICA) has nothing to do with 'Virtual Inheritance' (GVI).

In this context Resolution Inheritance (RI) will resolve an ambiguity (either MOA or ICA). The code below shows how RI resolves an Inherited Class Ambiguity (ICA) in which more than one instance of a base class is referenced in the inheritance structure.

For Example:

class Base{};
class Child1 : virtual public Base{};
class Child2 : virtual public Base{};
class Diamond: public Child1, public Child2{};
void main()
{
  Base* base_ptr;
  Child1 child_1;
  Child2 child_2;
  Diamond diamond;
  base_ptr = & child_1;
  base_ptr = & child_2;
  base_ptr = & diamond;
}

In the above code sample. The 'virtual' keyword for 'Base class inheritance' (by the children Child1, Child2) will resolve the Inherited Class Ambiguity (ICA) diamond problem (thus the resolution aspect/mechanism).

If the 'virtual' keyword was not present an 'ambiguous' compile time error would result because the compiler is not sure 'which base class' to use (ICA). Should it use the (potential) instance in Child1 or Child2?

The C++ syntax mechanism of the virtual keyword gives rise to the language specific (C++) and context specific (diamond problem) meaning of Resolution Inheritance (RI) as a conceptual semantic resoultion mechanism (i.e. an intention to 'resolve' the ICA ambiguity). As such, the CONCEPTUAL semantic meaning of Resolution Inheritance (RI in C++ and diamond problem context) is as a resolution mechanism to ensure only one 'copy' of the Base state space is implemented.

The use of the virtual keyword (RI resolution aspect) does not detract from the language independent (CONCEPTUAL) meaning of General Virtual Inheritance (GVI control/polymorph aspect). Furthermore the example C++ code above exhibits potential General Virtual Inheritance (as in the control/polymorph aspect) as a major feature of its capabilities even within this context (the diamond problem).

Note, the semantic mechanisms (i.e. an ICA resolution mechanism) for the C++ language specifcation are syntactic mechanisms by definition (i.e. the syntax of C++ 'virtual' keyword for ICA resolution). This 'virtual' keyword in C++ does not detract from the conceptual semantics of General Virtual Inheritance (GVI) when used in a language independent context (as defined in this article).

The term Resolution Inheritance (RI) should be used to qualify the effect of the 'virtual' keyword in an ICA/C++/Diamond context). This (RI) implies the 'resolution aspect' of the C++ virtual keyword syntax mechanism. Note that even in this context (C++/Diamond) the general meaning (control/polymorph mechanism) holds true. General Virtual Inheritance (as defined in this article) exists within the inheritance infrastructure for the diamond problem (as shown in the High State Tracker example below).

In C++ the GVI computing logic of control ALWAYS coexists with RI phenomena. Thus a 'Diamond' type class (as given in the code example below) may implement virtual methods that are controlled by the 'Base' parent.

[edit] C#

Section in progress.

[edit] C# Method Override Ambiguity (MOA)

C# uses the 'virtual' and 'override' keywords for method overriding. Method Override Ambiguity (MOA) is an Implementation Inheritance (II) phenomena whereby the implementation of a base class method is 'overridden' in a derived class.

The use of the 'virtual' keyword should not be confused with Virtual Inheritance (VI). The Human Impersonator example below shows that the C# virtual keyword does not imply the existence of virtual code elements. MOA is a Resolution Inheritance (RI) phenomena whereby a choice between a fixed object and a castable object is made.

C# uses Resolution Inheritance (RI) the same way C++ does for method overriding. Differing from C++, C# requires the additional keyword override modifier to produce a fixed behaviour in the derived class (fixed object Vs. castable object - see below).

Normal method overriding is limited to the context of the object's current casting.

For Example:

  // Human Impersonator example
  //
  using System;
  //
  public  class Human
     {
     public virtual void   Eye_color() { Console.WriteLine("Eye color is : Blue"); }
     }
  public  class Mutant : Human
     {
     public override void  Eye_color() { Console.WriteLine("Eye color is : Yellow"); }
     }
  public  class Test_driver
     {
     static void Main()
        {
        Human  human                  = new Human();
        Mutant mutant                 = new Mutant();
        Human  human_impersonator     = mutant;
        //
        mutant.              Eye_color();
        human.               Eye_color();
        //
        human_impersonator.  Eye_color();
        }
     }
  // Test_driver output
  //
  // WITH     -  'override' keyword for Mutant : Output is 'Fixed'
  //
  // Eye color is : Yellow
  // Eye color is : Blue
  // Eye color is : Yellow
  //
  // WITHOUT  -  'override' keyword for Mutant : Output is 'Castable'
  //
  // Eye color is : Yellow
  // Eye color is : Blue
  // Eye color is : Blue
  //

Resolution Inheritance (RI), for 'Method Override Ambiguity' (MOA), is instantiated using the C# 'virtual' and 'override' keywords as shown above.

The Human Impersonator output compares fixed to castable behaviour.

In the case where the design intention supports impersonation, the castable design having MOA is preferred over the fixed design without MOA. The example shows that MOA is NOT an inherent problem in design architectures.

The 'impersonation' above is a good example of the desirable functionality of MOA. Real world examples of impersonation are evident in high security systems where security proxies are used to 'impersonate' clients for access requests. In this design context security proxies improve the overall performance, implementation and maintainability of such systems.

MOA in any language is only a problem if the program architecture was not designed correctly. Having behaviour implemented as a castable object or a fixed object is dependent upon the design intentions of a good software architecture.

[edit] See also