Monday, August 17, 2009

Object Oriented Programming or "The Kids, These Days!"

It began in the mid-90s... the definition of OO programming started to wander. Before then, it was simple: OO was the trinity: inheritance, polymorphism and encapsulation. Most OO implementations supported some additional concepts such as data hiding or metaprogramming, but these were essentially their own fields of implementation and interest, only tangentially related to OO.

Over time, implementations began to become more entrenched as camps of OO theology. Java developers began to believe that data-hiding, interfaces and single-inheritance were core OO. Python and Ruby developers believed that metaprogramming and introspection were core OO. Smalltalk developers believed that the world was populated by idiots who could barely tie their shoes, much less be trusted with compilers. They're all wrong, of course (well, the Smalltalk folks might be on to something, but the Haskell people want to discuss the lack of rigor in their definition of "shoe").

Object oriented programming is still what it always was: a way of abstracting data using three basic tools. It's not the be-all, end-all of software design, and new ideas aren't to be judged as right or wrong, purely on whether or not they can be shoe-horned, retroactively into the definition. Equally, no language I've ever seen gets it completely right, and no language is unsuited to OO programming concepts, regardless of how much sugar they may lack. C (not to mean C++) is a fine language for OO development. Perl 5, interestingly, doesn't provide an OO system, only the basic tools required to build one. Python has a fairly robust object model, but one that many complain was "boiler plated on" to the core language (that's changing). Languages like Java integrate the object system so deeply into their core that you can't escape them, no matter how simple the task.

But none of this matters. Let's go back to first concepts and review what an object is and why it's a programming concept. Later, I'll get into why it's not a development concept, and review why that's a different thing entirely.

Inheritance is the first OO concept. It is fairly simple. A dog is a mammal. If we know what a mammal is, then we only have to describe what a dog has that's different from mammals in general. For example, a dog is a highly social/pack-oriented mammal that has a highly developed sense of smell, tends to be of medium size for the animal kingdom, and produces a largish litter of young. That's basic inheritance. There's no mystery, just a way of describing data in terms of its structure as unique from lesser-defined data types. The concepts of abstract types and of styles of single vs. multiple inheritance and traits/interfaces all fall out of this core idea, but they are not fundamental to the idea.

Polymorphism is up next. This is where you have a dog, but you want to bring it with you on an airplane. The airline has rules for how you bring a mammal onto the plane, so you tell the person at the checkin that you have a mammal. Now they know exactly how to deal with it. It's the same in OO programming, and exactly that simple. From this, we have derived many complex concepts, and every language implements polymorphism differently because of how deeply it ties into your parameter-passing mechanism, your data-hiding model and your type system. However, those are implementation details. OO is, again, a simple concept and straining it to include language-specific implementation details is only useful when engaging in language holy-wars. Notice that polymorphism relies directly on inheritance. There is no separating polymorphism off as its own concept in a world without inheritance. Polymorphism implies the existence of behaviors such as a dog's ability to run, nap or fetch. It is these behaviors which are polymorphic (all animals can sleep while only mammals can nurse their young).

Encapsulation is a bit what it sounds like. When you say that a dog has hair, you're not describing a unique concept. You're simply referencing a previously defined data type ("hair") and encapsulating it within the definition of a dog. Now, when you say, "here's a dog," I can ask, "what color is the dog's hair," and it makes perfect sense. You don't have to consult some external resource to answer the question, you just look at the dog and see that it has hair, and then look at the hair's color.

Now we can construct an object. Objects are data structures which embody polymorphic behaviors via inheritance while, simultaneously, providing encapsulation. A complete example using our dog would be the whole dog. A dog is an animal; it can be treated as one, and should behave abstractly like any other animal, though it might possess its own unique behaviors as well. It also contains all of the traits that one associates with dogs, many of which are full-fledged objects of their own (a heart that beats, a vocal apparatus with which it barks, etc.) All of these things describe a dog.

Now, that's the abstract. In practice, programming languages need to be able to describe all of this and use it, so there are two additional items: instantiation (the ability to bring an instance of an object into being); and members (encapsulated objects or primitive types—for those languages that distinguish). These aren't truly OO concepts, but implementation details common to nearly all OO languages.

Further complicating the issue are language features that have grown out of OO. Entire realms of these features exist, some rivaling the power of OO itself (metaprogramming comes to mind). Inheritance, for example, has been implemented as single, multiple and Java-like interface-augmented single. None of these are inherently wrong, nor are they part of the nature of OO programming.

Then there are software design concepts. Static classes, static members, privilege models, accessors, design patterns and so forth are all examples of software design and development tools and concepts which are valuable when interacting with OO languages and architecture. However, it's important to understand that OO exists on its own without these concepts. They help us to produce code that functions using OO, but a language which had none of these features and software that was designed without their benefit would still be "OO."