views:

152

answers:

5

I've been racking my brains over inheritance for a while now, but am still not completely able to get around it.

For example, the other day I was thinking about relating an Infallible Human and a Fallible Human. Let's first define the two:

  • Infallible Human: A human that can never make a mistake. Its do_task() method will never throw an exception
  • Fallible Human: A human that will occasionally make a mistakes. Its do_task() method may occasionally throw a ErrorProcessingRequest Exception

The question was: IS an infallible human A fallible human OR IS a fallible human AN infallible human?

The very nice answer I received was in the form of a question (I love these since it gives me rules to answer future questions I may have).

"Can you pass an infallible human where a fallible human is expected OR can you pass a fallible human where an infallible human is expected?"

It seems apparent that you can pass an infallible human where a fallible human is expected, but not the other way around. I guess that answered my question.

However, it still feels funny saying "An infallible human is a fallible human". Does anyone else feel queasy when they say it? It almost feels as if speaking out inheritance trees is like reading out statements from propositional calculus in plain English (the if/then implication connectives don't mean the same as that in spoken English). Does anyone else feel the same?

+5  A: 

In this case I would say a parent class is the answer: FallibleHuman inherits from Human, as does InFallibleHuman.

Daenyth
+8  A: 

"It seems apparent that you can pass an infallible human where a fallible human is expected, but not the other way around"

This is only a correct assumption in a certain context. Break it down this way:

  1. If the logic of your system requires to be passed a human that will make mistakes, then this is not correct.

  2. If the logic of the system doesn't care about what the human will do, then this is correct.

In other words it totally depends on the requirements of the system to determine the answer to the question "IS an infallible human A fallible human OR IS a fallible human AN infallible human?".

The fact that the logical objects have been anthropomorphized is probably more confusing than anything, because it seems like your confusion is stemming from a philisophical standpoint rather than a logical one. Replace "infallible human" and "fallible human" with "object X" and " object Y" and it may clear up the thinking for you.

womp
+1. Excellent point. These kind of metaphores to explain objects relationships generally fail; they often add little or none clarity and cause non-problems to become issues.
Juan Pablo Califano
I agree with what you say, but OO has been taught to us with the real world objects in mind with the aim of trying to model relationships between them, etc... that when we do encounter such situations, it feel outlandish at times.
dhruvbird
Shel Silverstein has a poem called _The Zebra Question_ where someone asks a zebra if he's black with white stripes or white with black stripes. The zebra doesn't answer directly...but descends into a litany of similar questions it might ask about the questioner ("are you good with bad habits, or bad with good habits?") Because the zebra won't shut up the guy states: "I'll never ask a zebra / About stripes / Again." :)
Hostile Fork
A: 

I agree with Daenyth...

Since once can never make mistakes and one does, logically this is the answer.

Contract-wise if a method expects a human that makes no mistakes it must not get one that does and if it expects one that does it must not get one that doesn't.

A base class of a human that may or may not make mistakes it the answer.

Danny Varod
+2  A: 

The primary purpose of inheritance is provide common functionality and describe commonality between classes. I would suggest that your description of the characteristics of the two humans (infallible and fallible) is distracting and causing the confusion.

What is "common" about humans? All humans have a public "do_task()" method and a private/protected "do_something()" method. So we describe that it a super class called "Human"

public abstract class Human
{
    // describes commonality
    public abstract void do_task();

    // provides common functionality
    protected virtual void do_something()
    {
        throw new Exception("I made a mistake");
    }
}

and now the "inherited" classes implement their own specific logic for the do_task() method but they share the common functionality of the protected do_something() method

public class InfallibleHuman : Human
{
    public override void do_task()
    {
        try
        {
            do_something();
        }
        catch
        {
            // never throw an exception
            // because I never make mistakes
        }
    }   
}

public class FallibleHuman : Human
{
    public override void do_task()
    {
        do_something();
        // always throw an exception if
        // something goes wrong because I'm accountable
        // for my own actions
    }
}

Now, we've used inheritance to describe commonality between humans and provide a default, common implementation, but the sub-classed version have added specific behavior that we used the word "Fallible" and "Infallible" to describe, which has nothing to do with inheritance.

Now, if you have something that is using humans, and it will accept any human being, you could use InfallibleHuman or FallibleHuman.

public void ImPrettyTolerantOfMistakes()
{
    try
    {
        Human anyHumanWillDo = new FallibleHuman();
        anyHumanWillDo.do_task();
        Human anotherHuman = new InfallibleHuman();
        anotherHuman.do_task();
    }
    catch
    {
        // I'll take care of a human
        // making a mistake
    }
}

But if you are using something that is intolerant of humans that make mistakes, you would use a perfect human...

public void ImIntolerantOfHumansWhoMakeMistakes()
{
    InfallibleHuman onlyAPerfectHumanWillDo = new InfallibleHuman();
    onlyAPerfectHumanWillDo.do_task();

    // if this guy fails, I'm dead meat
}

I hope things clears things up for you a bit.

Cheers, Dave

Dave White
A: 

Exceptions are normally thrown under exceptional circumstances. If the point of a fallible human is that it makes mistakes, why would there be an exception?

As for the question at hand, I would say that they cannot inherit from each other, but from a parent Human class. They are both types of humans.

The Real Diel