
OOP practiced backwards is "POO" - raganwald
http://github.com/raganwald/homoiconic/blob/master/2010/12/oop.md#readme
======
neilk
Skillful practictioners of OOP, even in languages like Java, know this stuff
already. It's just that the language leads newbies astray by making
inheritance such a prominent concept.

To a first approximation, inheritance is always wrong. The Design Patterns
book advocates composition -- building up an object out of smaller ones --
over inheritance. Yeah there's more work to delegate messages around, but if
you didn't like typing you shouldn't have picked Java (or, use an editor that
makes this easier).

Also, when trapped in languages like Java, define behaviour in terms of
interfaces rather than inheritance. Interfaces are exactly what raganwald is
talking about -- they define the ability of something to respond to methods,
but are decoupled from any parent-child relations.

~~~
swannodette
Dynamic languages like JS, Ruby and Python could greatly benefit from explicit
support for interfaces as well. I'm enjoying the fact that Clojure brings this
powerful abstraction to a dynamically typed language.

~~~
russellperry
This might make sense for Clojure (I haven't used it) but in my years of Ruby
programming (after 10 years in Java and C#) I have _never_ thought to myself,
man I'd love to have an interface here. Ruby's lack of class-level contracts
is essential to its idiomatic nature, a strength not a weakness, imo.

~~~
gregwebs
Generally speaking I like interfaces, but Ruby is so dynamic that you couldn't
use them for compile-time guarantees. Interfaces could only get you a slightly
nicer way of dynamic duck typing. I wouldn't really call all of the dynamism a
strength though - one of the limiting factors of compile time evaluation here
is that a method can later become undefined- when is the last time you needed
that?

~~~
steveklabnik
Actually, undefining methods on an object because such an idiom that Ruby 1.9
introduced a new base class into the hierarchy: BasicObject. [1] This is now
the new root class, above Object.

1: <http://www.ruby-doc.org/core-1.9/classes/BasicObject.html>

~~~
gregwebs
Yeah, that is the 1 case, and ActiveSupport has had a BasicObject for a while
now. This is another case where proponents would say it is great that you can
undefine a method, but I would say that is a hack for lack of any namespace
management. Now that there is a BasicObject I am not sure that there is any
practical use for undefining a method- probably only for dealing with
namespace collisions, which again seems to point out a language flaw, not a
feature of dynamism.

------
lukev
>the abstract ontology is derived from the behaviour of the individual
specimens, the ontology does not define the behaviour of the individual
specimens.

In other words... Do you like Plato, or do you think Aristotle had it right?

There are lot of cool isomorphisms between philosophy (particularly
metaphysics) and software design.

~~~
rbxbx
Any chance you could expand upon this? I'd be interested to read more about
this (and other) parallel/s.

~~~
msluyter
I think this is a reference to Plato's Theory of Forms, in which every object
we see partakes of some idealized (static, eternal, and real) form (ie, is an
instantiation of a class). Except... in Plato's theory, everything is a
somewhat corrupted or imperfect image of its form. The theory has a lot of
problems (the third man problem, for example).

See: <http://en.wikipedia.org/wiki/Theory_of_Forms>

~~~
lukev
Well, yes. There's various interpretations of what kind of existence Plato
thought the Forms actually had - whether he believed in a literal "realm of
the Forms" or not. And while you'd be hard pressed to find someone who
actually subscribes to the theory of Forms these days, there are a lot of
things in, for example, the philosophy of Mathematics that smell a lot like
it.

I think the idea of Forms is still quite valuable

Aristotle takes kind of the opposite tack - he is also very focused on
building ontologies and taxonomies, but he views them as constructions of the
intellect imposed upon their subjects, rather than being the most fundamental
reality of the subject prior to its actual being. It's pretty much the same
distinction ragenwald talks about in the OP.

As for the general isomorphism between metaphysics and philosophy, you can
find it almost everywhere, depending how hard you want to look (and how far
you want to stretch your metaphors...). But metaphysics is largely concerned
with the types of things and entities in the world, and how they can possibly
interact. If you think of the "software space" as its own universe, it's
pretty easy to draw parallels. Forms and Categories are low hanging fruits,
obviously, but a few other parallels spring to mind:

\- Kant's seperation between Phenomena and Noumena relates to the difference
between interface and implementation, as well as to the concept of
abstractions in general.

\- How a software component's "epistemology" (how it "knows" about other
components in the system) works can be compared to different philosophers - do
they operate on a consistently readable shared state (an empirical world?) or
do they request information from a central broker service (God brokers sense
impressions, ala Berkeley?)

\- Berkeley's idea of direct impressions only in the mind has some
relationship to the concept of laziness.

\- etc.

I'll try to think up some more and post them later. It's less that you can
write a paper on the startling isomorphism between theories, and more that
it's really easy to use software metaphors to describe philosophy and vice
versa (though software tends to be much more concrete, obviously).

~~~
russellperry
"Aristotle takes kind of the opposite tack - he is also very focused on
building ontologies and taxonomies, but he views them as constructions of the
intellect imposed upon their subjects, rather than being the most fundamental
reality of the subject prior to its actual being."

Well, not exactly, and in fact this would turn Aristotle into his metaphysical
opposite: a nominalist in the mold of Occam.

For Aristotle the formal cause of a substance is in fact absolute, every bit
as real and 'prior' as with Plato, the big difference between the two being
the question of epistemology, or how we become acquainted with the form to
begin with. Yes, Aristotle argues that we know the form of a thing from
experience, but the form of that thing, and the abstractions we produce from
many experiences from similar things, are as real as with Plato and, as in
Plato, point to higher, more organized spiritual structures that comprise
ultimate reality.

Call me when somebody comes up with a Whitehead-ean programming paradigm.

------
chwahoo
It is an interesting observation that the brittleness of inheritance
hierarchies stems from the fact that they have a semantic meaning in the
program and are not just logical classifications. A simpler (and well-
accepted) explanation for inheritance's problems is that it is a code-reuse
implementation technique that people mistakenly use for software design. I
suspect these explanations are related.

I'm not sure I completely followed your ideas about hierarchical
classification being more useful for testing... perhaps because using animal
categorization as an example was difficult to follow since people don't write
tests for animals. What does it mean to have hierarchies for tests and what
benefits does it provide?

------
Periodic
I think this problem may be while I enjoy functional programming so much. I
believe that the functional programming tends to build from the data up, from
the actual instances it then adds definitions of behavior, instead of trying
to group behaviors and fit the various arrangements of data in that hierarchy.

Usually you start with some data. It might be some loose tuple in a dynamic
language like erlang, or an algebraic data type in a language like Haskell
(not that there are many like it). It's like saying, I have a Cat or I have a
Bat. You haven't said anything about the two yet other than that they are
different. You could then add more information, such as the number of legs or
color. You add behavior by defining functions that can act on that data and
create changes from them. For example, two cats can reproduce, so you define a
function that takes two Cats and makes a kitten (new Cat). Bats might also
reproduce, so you can write the function more generally to take any two data
objects that have the minimum prerequisites (such as identical internal
representations) and produces a new one that's a combination.

When a new data type is needed, you simply add it and it automatically gains
all this functionality based on its form.

Essentially, OOP seems to want to start from the behaviors and have that
define the data. When writing functionally I tend to define the data, then
build behavior on top of it which is driven more by the form of the data than
any idealized class hierarchy.

I'm not sure I'm explaining this terribly lucidly, but hopefully this can
start a discussion among the more articulate posters.

~~~
TimJYoung
Most developers that I know of that have been using OO languages for some
time, including myself, also usually start with the data items being dealt
with and proceed from there. In fact, it's not particularly natural to do it
any other way. If you've got a window, then it's a Window class, with all of
the relevant behaviors (methods) added afterwards. If you're dealing with a
file, then it's a File class, and so on.

------
arohner
Another interesting facet of the "natural ontologies" argument is that the
history of Zoology is a series of "bug fixes" where we got the ontology
_wrong_.

Leaving out changing requirements and DNA mutations for a second, there have
been massive changes to the "official" ontology as we discover new species or
examine DNA and have to say "oops, turns out, the platypus doesn't derive from
birds at all".

------
russellperry
"What if objects exist as encapsulations, and the communicate via messages?
What if code re-use has nothing to do with inheritance, but uses composition,
delegation, even old-fashioned helper objects or any technique the programmer
deems fit? The ontology does not go away, but it is decoupled from the
implementation. Here's how."

This is standard OOP 101 advice. 'Prefer encapsulation to inheritance' has
been axiomatic in OO literature for over a decade. GOF and all the GOF-derived
texts emphasize this.

OOP <> Inheritance

Inheritance is only one tool in the OOP toolbox, and probably one of the least
important. OOP itself is only one conceptual tool in the programmer's toolbox,
alongside procedural and functional tools. Learn them all, learn their
strengths and weaknesses, and learn how to apply the right tool to the right
problem.

------
abecedarius
_Design-by-Contract is protected by various business restrictions so it has
nobody but itself to blame for its unpopularity_

What's this about? Some patent or something?

I'd guess this is a reference to Bertrand Meyer's company. Since I learned DbC
from Liskov & Guttag's excellent book, which came out before Meyer's, I never
had much reason to look into Meyer or Eiffel even though they became
practically identified with DbC.

------
CUViper
I like the way the C++ FAQ explains the problems of "is a" inheritance,
especially the examples of Circle-is-an-Ellipse.

[http://www.parashift.com/c++-faq-lite/proper-
inheritance.htm...](http://www.parashift.com/c++-faq-lite/proper-
inheritance.html)

~~~
Groxx
That's a particularly accurate, bash-you-over-the-head-until-you-get-it
explanation of the problems of inheritance. Nice link. I should really read
through that whole FAQ/FQA some time, it's full of good stuff.

I, personally, think of inheritance as it implies near the end: if A derives
from B, A _must_ effectively _be_ B in all B-exposed methods. It can optimize,
but it cannot change; A must pass _any_ test B would pass, or it's not
actually a B.

But _lots_ of code violates this. I think it's because a lot of people learn
inheritance with the real-world connections in mind, and it's frequently
taught to beginning programmers as a golden bullet. It can do a lot, but it
has subtle surprises until you get better at programming.

------
lr
I couldn't agree more. To me, encapsulation is the most powerful part of OOP.
I learned this from Allen Holub, and it has been part of my mantra about OOP
for years. It is what makes WebObjects such a powerful web framework, and why
I am happily using Grails today. This reminds me that I really need to do a
screen cast on why encapsulation is such an important feature of a web
framework.

~~~
olivolive
The essays at the beginning of Holub on Patterns completely changed my
understanding of OOP.

Implementation inheritance violates encapsulation. So do getters and setters.
They let code outside your object rely on your implementation and make your
system brittle.

------
dawgr
OOP in my country is poo.

Programación Orientada a Objetos.

~~~
Avshalom
Out of curiosity whats poo? or more explicitly what (if there is one) is the
common, non vulgar, childish version of mierda?

~~~
delano
The answer to your second question is poop.

------
ZeSmith
Fun thing is that "object oriented programming", in French, is "programmation
orientée par objets", which is usually shortened to "POO" (pronounced Pay-Oh-
Oh).

------
kevindication
The observations are an interesting expansion on the idea of Duck typing.

~~~
swift
Indeed, duck typing and structural typing are what immediately came to mind as
a solution for the brittleness of inheritance hierarchies that the OP
describes.

------
parasubvert
I think you've hit on something very important, essential, in the problem with
OO-as-taught. This is something that is known in many quarters of skillful
practictioners, but missed by most schools or beginners. I think the first
part of this article is misleading, in that it waxes philosophical about the
drawbacks of defining things in an ontology. But then it then proceeds to
figure out a better way to model things as an ontology! The issue isn't with
ontologies -- yes, slapping a hierarchy or meronymy on something isn't
perfect, but it's pretty useful when organizing concepts.

The fundamental problem with OO inheritance, is that it is _not_ ontological
or mathematical inheritance! OO inheritance has almost no relationship to
thousands of years of what "is-a" means -- i.e. subset. It's backwards -
subclasses are extensions, or _supersets_ of their parents.

The way to implement inheritance correctly is "specialization by constraint",
i.e. you define a subclass by the constraints it has on its superclass. This
is what's happening in the latter part of the article, with design-by-contract
and test cases for your various classes. This is also, by the way, how
ontology languages like OWL work, and in part why they're so hard to learn/use
-- their notion of inheritance and "subclassing" is the mathematical notion
(i.e. more like subset), and the opposite of OO programming languages, so we
have 25+ years of history to unlearn.

I suspect the reason OO inheritance took the path it did was for simple
expediency on the part of compiler writers & language designers.
Specialization by constraint ain't easy to implement declaratively.

~~~
limmeau
I don't get how subclasses are _super_ sets of their parents. The set of
instances of a subclass is a (usually proper) subset of the set of instances
of its superclass (in any mainstream class-OO language).

Also, writing a subclass definition _can_ be seen as adding constraints (of
the form "must also have a bla() method returning an int").

------
Xuzz
Is this an argument for prototype-based programming? I don't understand all
this stuff well enough to provide a real opinion, but it seems to me that is a
solution to the issues he brings up.

~~~
pak
Yeah, it seems that prototype-based programming fits his needs better. With
prototypal inheritance you make no assumption that what you inherit from is a
strict superset of the class. It's more like saying "This object is _like_ so-
and-so, except..." every time you create a link in the inheritance chain, and
that fits the way people classify things a little better. Steve Yegge put it
best: "The most specific event can serve as a general example of a class of
events."

[http://steve-yegge.blogspot.com/2008/10/universal-design-
pat...](http://steve-yegge.blogspot.com/2008/10/universal-design-pattern.html)

~~~
Xuzz

        Steve Yegge put it best.
    

He often does.

------
richcollins
Not sure what abstract ontologies have to do with expressing instructions for
my computer to execute. I use inheritance as a tool to share behavior across
objects. It works nicely for that.

------
cperciva
Object Oriented Programming Systems are (abbreviated) mistakes.

~~~
cperciva
I wonder, did the people downvoting this not see the joke, or did they see the
joke and decide it wasn't funny?

------
iskander
This is roughly how I program using OCaml's module system. Does anyone else
prefer higher-order modules as the basic unit of program structure?

------
devrim
thinking OOP as a solution may lead to an article like this whereas it merely
is a vehicle. you may or may not use it.

problems of OOP is explained in Go Language video by Rob Pike*, however very
intellectually stated arguments in this article are mainly false.

<http://www.youtube.com/watch?v=rKnDgT73v8s>

------
gte910h
Many of the languages I use already in an object oriented style use message
passing/signatures not compiled in mandatory type hierarchies.

Python, Objective-C, Smalltalk and even C++ in some ways all do this.

I suggest if you feel like the OP does, you use one of them instead of java or
C# or whatever that dude is using.

------
st3fan
And "Functional Programming" is an anagram for "Malfunctioning Program". Yay
for rants.

------
adnam
It's actually called POO in Spanish: Programación Orientado a Objetos

------
ben0x539
The obvious solution is to stop getting OOP backwards, then.

------
someaccountful
Perl object-oriented programming = POOP.

