views:

644

answers:

6

Just came across this quote in a book on OOP that I'm reading,

A child is only allowed to augment functionality and add functionality. A child is never allowed to remove functionality. If you do find that a child need to remove functionality, this is an indication that the child should appear before the parent in the inheritance hierarchy!

But my question is, isn't this what overriding does?

+3  A: 

You can remove functionality with overriding. But normally you use it to change the behaviour. To let the class behave as it should be.

If behaviour is removed then it is very often a sign of a bad class design.

Gamecat
So really in C#, everything inherits from system.object, correct? And you either change the behavior of the methods in system.object, or you just don't use them, but you never remove them.
GregD
Not always. What about the NullObjectPattern :)
OscarRyz
Does C# have such a thing? Remember that I am a beginner. In my mind, null is still *something* despite the fact that it's representative of the absence of an object. That's still a definition of something.
GregD
+1  A: 

When overriding a method, it is possible to call the parent implementation at some point during your override, so using overriding to add functionality to the parent implementation.

Ian Nelson
+3  A: 

The child cannot remove functionality - it can alter it, but you can't, say, make a public method private.

The point of inheritance is that you can handle the child as if it was the parent. If you has a 'Person' superclass a 'Employee' subclass, it would make no sense for the Employee class to have no breathe() method.

Brabster
I wonder how this applies to Ruby
OscarRyz
A: 

And that's kinda why overriding (and in general, any virtual members) is something that should be done very carefully... In fact, generally, when overriding, you should try to code both the base class and the derived class, so that the derived class implementation first calls the base implementation, and then executes it's additional functionality...

but this principle is not enforced in OO languages, and is often violated...

Example of why this is bad

Imagine you have CompanyA designs Type ( class ) Phone

namespace CompanyA {
   class Phone {
       public void Dial() {
        // do work to dial the phone here
       }
   }
}

No iagine Company B defines another type BetterPhone, that uses Company A's Phone as base type...

namespace CompanyB {
   class BetterPhone: CompanyA.Phone {
       public void Dial()  {
           Console.WriteLine("BetterPhoneDial");
           EstablishConenction();
           base.Dial();
       }
   }
}

Now CompanyA, whose Phone class is in use by other Companies (Company C, D, etc.) decides that establishing a connection is a useful thing to have in the class, and modifies CompanyA.Phone, adding an EsatblishCOnnection() method as well, perhaps with a different implementation... Until we had the "new" keyword, this scenario would have broken CompanyB's BetterPhone class... the first time they attempted to use the new base class.

Charles Bretana
Not really. If the child does a very different thing ( take state pattern for instance ) why would it call the base impl first? That sound more like template pattern to me, and I don't think is an OO principle. Probably a practice, but not a principle.
OscarRyz
Because the person/persons who wrote the base class whose implementation you are overriding may have other members in that class that are dependant on the behavior you have eliminated or modified...
Charles Bretana
That reminds me this: http://tinyurl.com/DesignToInheranceOrProhibitIt That talks about exactly what you're talking about. It is better not to take chances and design your class properly to allow inheritance on purpose or otherwise mark the method as final ( you can make it non final later )
OscarRyz
For is not the caller fault not to call the base class ( but fault of the base for not making sure it will always be called ) and since as you said that is not enforces by OO prog langs, I think that article makes sense. :)
OscarRyz
+1  A: 

No. Actually you would be augmenting functionality ( in a negative way )

Let's say your new functionality is "do nothing" but the method, what the clients of your code see is still the same interface

You cannot have a subclass that remove a method of its parent.

This is possible

class Parent {
    public void method_one(){ 
        print "Hello";
    }
}

class Child extends Parent {
     public void method_one(){
         // do nothing
     }
 }

But this is not:

class Parent {
    public void method_one(){ 
        print "Hello";
    }
}

class Child extends Parent {
     // Attempt remove the method visibility, thus remove funcionality 
     private void method_one(){ 
         // do nothing
     }
 }
OscarRyz
A: 

If your child requires to remove functionality of parent, then parent must be declared as Interface. Because Interface is mechanism which defines contracts that must be abide by its implementor.

E.g.


public interface IContract
{
  void DoWork();
}

public class BaseContract: IContract
{
 public virtual void DoWork()
 {
  //perform operation A
 }
}

Now if you want to declare new EnhancedContract class, you can derive it either from BaseContract or IContract depend on requirement. If you want to do additional operation to operation A of base, you can inherit it from BaseContract as shown below.


public class EnhancedContract: BaseContract
{
  public override void DoWork()
  {
   //perform operation B
   base.DoWork();
   //perform operation C
  }
}

But if you are not interested in doing operation A in DoWork method of EnhancedContract, then inherit it from IContract.

This assures that EnhancedWork will perform DoWork(), but it is not guaranteed to do 'operation A' in it.


public class EnhancedWork:IContract
{
  public void DoWork()
  {
   //perform operation D
  }
}

This is important for understading because it will stop user from doing below casting.


EnhancedContract e = new EnhancedContract();
BaseContract b = e;

I believe all these operations are important while understanding Open Closed principle, Liskov substitution principle.

Thumb rule for inheritance is "Put additional functionality into existing one".

Rakesh Gunijan