What is Object Oriented Programming, anyway?

Before I embark on a series of potentially ill judged posts regarding some aspects of OOP, perhaps it would be a good idea to try to define what it is.

This is somewhat dangerous territory. I am reminded of the final sections of Stewart Lee’s masterpiece “90’s comedian” where he draws a chalk circle around himself and the microphone, repeating a ritual practised by medieval clowns to protect themselves against persecution from heresy (I’ll hopefully be able to link to this soon).

Other people’s attempts

Wikipedia’s attempt is the best example to start with.

Object-oriented programming (OOP) is a programming paradigm that represents concepts as “objects” that have data fields (attributes that describe the object) and associated procedures known as methods. Objects, which are usually instances of classes, are used to interact with one another to design applications and computer programs.[1][2] C++, Objective-C, Smalltalk, Java, C#, Perl, Python, Ruby and PHP are examples of object- oriented programming languages.

A little taster there of the vagaries that are waiting for us. One can almost see the scars from previous edit wars.

What about the folks who came up with the idea?

The C2 Wiki has enough different definitions that there’s even an index page listing all the variants.

From all these pages, my favourite snippet:

OO is not a well defined concept — Jonathan Rees

I’m inclined to agree with that, on the above evidence.

Baby steps

If we are unable to define OOP, can we distil a sentence out of all that noise? Well, thankfully, someone already has:

Procedural code gets information then makes decisions. Object-oriented code tells objects to do things. — Alec Sharp > – a bit of a meta reference, but there we go

Finally some tersity! C2Wiki provides some more colour.

I’ve been trapped in OO land recently, and tell don’t ask (TDA) has proved a neat little principle to guide the design.

We’ll back off from adding another definition of OOP; we’ll even omit any explanation of why TDA is useful (more on this soon). Instead, we’ll start by attempting to pin down a rigorous description of TDA.

Definition : tell don’t ask

A function is tell don’t ask if information moves only from the caller to the callee.

This prevents the caller making decisions based on the callee’s state. This isn’t complicated or new, it’s just strict encapsulation.

I hear a cry at the back of the room: “That seems a bit dry. Can we have something a bit more concrete?”.

Ok, mysterious interloper, let’s explore some alternatives.

Other definitions (that don’t work)

Interloper : Hey! They do work! Why don’t we just say:

A function is tell don’t ask if it has void return type.

Narrator : Well, what about this counter-example: OutputStream ‘s write

public void write(byte[] b) throws IOException

Narrator : Now, the caller can catch IOException and infer something about the status of the write, and thus the state of the OutputStream .

Interloper : Ok, Mr. Pedant, how about this:

A function is tell don’t ask if it has void return type and never throws

Narrator : Ho ho, we’re getting there, but you forgot about the cavepeoples’ return value:

public class A {
    public void doThing(final B b) {
        final List<String> out = new LinkedList<String>();
        b.showThyself(out);

        // now we know all of B's strings. Stupid B!
    }
}

public class B {
    private final List<String> myStrings = ImmutableList.copyOf("a", "b");

    public void showThyself(final List<? super String> out) {
        for (final String s: myStrings) out.add(s);
    }
}

Interloper : Oh man. People still do that?

Narrator : Yes. I know. What can you do?

Interloper : *sigh. That does give me another idea though, how about this:

A function is tell don’t ask if:

  1. It has void return type
  2. It never throws
  3. All the function’s parameters are either classes, whose functions all obey 1 and 2, or primitives

Narrator : Now we’re getting somewhere. Have you considered this case, though?

public class A {
    public void doThing(final B b) {
        b.doThing(a);
    }

    public void aha(final String theSecretOfB) {
        // now we have the secret of B! Stupid B!
    }
}

public class B {
    private final String secret;

    public B(String secret) {
        this.secret = secret;
    }

    public void doThing(final A a) {
        a.aha(secret);
    }
}

Interloper : Oh man, this is getting seriously boring; ok, last go. Maybe add a clause to say that the caller can’t pass itself as a parameter?

Narrator : Well, yes, but then we can get around that by wrapping the caller inside some other class that we then pass into the function.

Interloper : How about we enforce that no parameter can contain the caller then?

Narrator : Well, that’s fine, but is the concrete definition that we now have more or less useful than the abstract one?

A function is tell don’t ask if:

  1. It has void return type
  2. It never throws
  3. All the function’s parameters are either classes, whose functions all obey 1 and 2, or primitives
  4. None of the function’s parameters may contain a reference to the caller, directly or indirectly

Interloper : Ok, I see your point. What about reflection, though?

Narrator : Well, once we start using reflection, all bets are off – we can’t even guarantee the privacy of fields, so attempting to define things with reflection in play is just pointless.

Protestations

  • What about queries?

I’d argue that the whole concept of ‘query’ is exactly the opposite of TDA, we ‘ask’ a question and then act on the response. This is a deliberate exclusion from our toolbox; we want to see if we can get by without it.

  • Can real programs really work this way?

Let’s find out! We’ll start with our tight definition of TDA, and perhaps we’ll find some species of program that are difficult to express. On the other hand, perhaps everything will work. Place your bets…now!

At this point, I am minded to reproduce some quotations on being restrictive that David Wheeler’s essay (on fixing unix/linux filenames) includes.

Seek freedom and become captive of your desires, seek discipline and find your liberty — Frank Herbert, Dune

Negative freedom is freedom from constraint, that is, permission to do things; Positive freedom is empowerment, that is, ability to do things… Negative and positive freedoms, it might seem, are two different descriptions of the same thing. No! Life is not so simple. There is reason to think that constraints (prohibitions, if you like) can actually help people to do things better. Constraints can enhance ability… — Angus Sibley, “Two Kinds of Freedom”

Next time

We’ll talk about how TDA programs express variance, and contrast that approach with how variance is expressed in functional programs. We might make the joke about non-functional programs, for the sake of tradition. See you then.