Skip to content

Train wrecks in functional languages

April 12, 2010

Recently @Steve_Hayes twittered the following:

Why are functional trainwrecks good and oo ones bad? What’s the conceptual difference?

Since twitter is a little inadequate to answer this question directly I’ll attempt to outline my view of the difference on this blog. I’ll first put forward the disclaimer that I’m certainly not an expert in functional languages. I’ve never let my ignorance get in the way of having an opinion before so why stop now.

Firstly lets start out by defining a train wreck in an OO context. Typically they would look something like this:

String postcode = order.getCustomer().getAddress().getPostcode();

The code above has the property that it tranverses fairly deeply into the object hierarchy effectively creating a dependency on that code from far away.

If we were to split that code up like follows:

Customer customer = order.getCustomer();
Address address = customer.getAddress();
String postcode = address.getPostcode();

We still end up with code that does the same thing but we might not describe it as a train wreck any longer. Whether the first or second form is better is probably a matter of style. They both suffer from the same problem which is violating the law of demeter.

Wikipedia has this to say about the law of demeter:

More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:

1. O itself
2. M’s parameters
3. any objects created/instantiated within M
4. O’s direct component objects

In particular, an object should avoid invoking methods of a member object returned by another method.

So the real problem with a train wreck is that it can be the sign of a violation of the law of demeter.

While I like the principle of the LoD in thoery, in practice it can be hard to follow sometimes so I have to question whether the odd train wreck is necessarily bad.

But anyway so far I haven’t really gotten into train wrecks from the point of view of functional languages. One question you need to asked is, is it even possible to have a train wreck in a functional language? You can certainly chain method calls together in ways that look a little like an OO train wreck but you’re not traversing an object graph so is it really the same?

In fact in functional languages things work a little differently with respect to functions and data. One famous quote from Alan Perlis is:

It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures.

It may be a generalization but good functional programs tend towards the 100 functions, 1 datastructure part and OO programs tend to fall in the 10 functions and 10 datastructures part.

In an OO language you generally want to design your objects to have as few dependencies as possible. Each class becomes a encapsulation boundary. A train wreck is a clear violation of that concept. In a functional language there are fewer core abstractions and the developer operates on them in a variety of different ways.

In fact this applies to not just to having fewer data structures but also to having fewer abstractions. Take Clojure for example. It uses the sequence abstraction everywhere. This allows us to string together functions in really interesting ways. Take this small example:

(map inc (take 5 (iterate dec 5)))

Here we’re stringing together lots of little function calls to achieve an interesting calculation. It looks like a chain wreck but isn’t really the same thing at all since it’s just working with sequences and values at each point.

So how about a more apples to apples comparison.

(def person {
  :name "Mark Volkmann"
  :address {
    :street "644 Glen Summit"
    :city "St. Charles"
    :state "Missouri"
    :zip 63304}
  :employer {
    :name "Object Computing, Inc."
    :address {
      :street "12140 Woodcrest Executive Drive, Suite 250"
      :city "Creve Coeur"
      :state "Missouri"
      :zip 63141}}})

Here we’ve idenfied the details for a person. Immediately we can see it differs from the OO version. Firstly rather than objects we’re using plain old maps. Rather than defining several objects to hold the address and employer details we chose to nest this data. The data can be accessed in a few different ways:

(-> person :employer :address :city)

or

(((person :employer) :address) :city)

or

(let [employer (person :employer)
      address (employer :address)
      city (address :city)]
  city)

All “train-wrecks” in their own manner. The difference I guess is that we no longer have the same boundaries we have with our OO code. By using maps to store our data we’ve now got access to many of the functions provided by maps. Maps are also sequences so we’ve got access to all functions that operate on sequences as well. Even our :keywords actually operate as functions. Actually come to think of it the map itself is even a function too. Can you see the whole – many functions, few data structures – thing in play now?

The LoD thing doesn’t really make sense in this view of the world, while in an OO world it certainly does.

Advertisements

From → Technical

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: