Starting to Understand Inheritance

Saturday, May 19, 2012

Software Inheritance

As a software engineer, as you spend more time in the profession, you will continually see software structured differently from how you would do it. Sometimes, you are just confused by the author's code, other times you understand and disagree with it, and yet other times you become so inspired by it that adopt its design. Recently, I've come across object-oriented code that makes heavy use of inheritance in its solution, and I have been actively confused by it due to its difficult reading level. I think I am finally coming to understand how to read code written in the inheritance style, and I'd like to share what I've found.

Initial Issues - Internal State

When first encountering inheritance, I interpreted it on a shallow level. I saw the 'extends' keyword, which means it 'inherits' from the specified class and can reference its variables and methods, but I never understood how its utilization could justify the higher maintenance cost of its slurred readability.

The first issue I had with reading inheritance-based code is sharing class properties. When I create a new class, I design it to minimize references to internal state. I use static methods as much as possible. Why? Those class properties are variables, unless they use 'final' keyword, and without foresight for possible values of these class properties, your methods can produce unexpected results.

So consider my surprise to see references to a base class' internal properties from an inheriting class! What could the author be thinking? Are you really sure you trust that that class-external variable will always be a valid value for your class? Holy buckets, Batman, this inheritance business seems to be a bucket of holes!

Towards Better Understanding

I was reading some Javascript code recently for an Ajax-y framework. The base of the app uses John Resig's simple Javascript inheritance, and subsequent objects extend from this base Class type. It seemed that the author was so influenced by inheritance that he wanted to force it into Javascript before considering his solution. I understood inheritance on a shallow level, but still - what is so necessary about inheritance?

After some research, I think I'm starting to understand the case for inheritance. The explanation offered on this Wikipedia page on Differential Inheritance was quite inspirational.
"To think of differential inheritance, you think in terms of what is different. So for instance, when trying to describe to someone how Dumbo looks, you could tell them in terms of elephants: Think of an elephant. Now Dumbo is a lot shorter, has big ears, no tusks, a little pink bow and can fly. Using this method, you don't need to go on and on about what makes up an elephant, you only need to describe the differences; anything not explicitly different can be safely assumed to be the same." - Wikipedia: Differential Inheritance
Ah, from this point of view, inheritance is a convenient way of saying "I need a class just like that one, but a little different." In other words, it is a programmer's feature for convenient customization. A bonus feature is that the inheriting class can be used in place of the base class by using type casting. (Short thought - isn't this ability better performed by using interfaces and a platform that accepting registering custom handlers?)

Issue Still Remains

While I do have a better understanding of inheritance now, my problem still exists: If MyClass inherits from BaseClass, I can't look at MyClass on its own because most of the real logic exists in BaseClass! This doesn't help when debugging these two classes, since BaseClass was designed to run one way, and MyClass might be changing the behavior of BaseClass in an incompatible manner. Sure, this may work, but it feels a bit fragile and unnecessary. I wonder if my understanding of the benefits of inheritance-utilizing code will grow as I continue to read it, but I hope it isn't a poison that infects my style.

2 comments:

  1. Subclassing is a way to create a class more specific than the class it derives from, yet with all (or most) of the behaviors of the super class.

    One of the best examples of specialization inheritance is the Smalltalk collection class hierarchy.

    At the top of the hierarchy is Object, the most general class of all. As you go down the tree, each class is more specialized to its purpose, and each implements the expected behavior for its class even if the method's name is the same. Adding an object to a Set is different than adding it to a list, but both are easy for a programmer to remember and apply.

    http://www.jmcsweeney.co.uk/computing/m206/collections_intro.php

    Much more can be said on the subject (and has) but I expect you've already found those resources.

    ReplyDelete
  2. Thanks for your comment, Thomas. I do have to look into Smalltalk someday, as it seems to have a more solid implementation of OOP. I like using inheritance for type hierarchies, as each level deeper adds one more constraint over its parent type.

    However, trying to read a system that makes heavy use of inheritance - this skill still escapes me. It is my understanding that one of the keys to bug-free code is to keep related code close together."Out of mind, out of sight" seems appropriate. That is, if a class' implementation depends on its parent in a hidden way, bugs could slip in as edge cases aren't considered. Two classes sharing state is the Mose maddening thing. Which property is whose responsibility?

    In short, inheritance seems to be a great tool, but I can't see it necessary in most cases. On the contrary, its misuse is harmful. Interface contracts often seem more appropriate. I may change my mind as I improve my skills, and see the light.

    I wonder if you have been in my position before, Thomas, as you were learning the art of OOP?

    ReplyDelete