Expressing the problem

Object-oriented languages are good at adding new data; functional languages are good at adding new behavior. Can we find a happy medium?

The answer: Sorta.

First I’ll explain what I’m talking about, with examples. At the bottom of this article I’ll talk about the lambda calculus. Oh and before that I’ll talk about something relevant to normal Ruby programming, in case that’s something you’re still into.

The problem

But first let’s start even simpler: we are going to represent addition in Ruby.

Further, the claim is that it’s hard to add new behavior. As an example of what that means, consider adding to_s for our little arithmetic language. Here are some ways to do that:

Open each class and add a to_s method. This can be done either by modifying the file directly (very possible if it’s in our codebase), or by using Ruby’s open classes. Ruby’s open classes are brittle when dealing with private data, so we should consider avoiding that.

Define subclasses, either via composition or inheritance, that add the desired debugging behavior. This would mean re-writing every use of IfThenElse.new with DebuggingIfThenElse.new, as needed.

Both of those options are OK, and will absolutely work perfectly in some situations. Let’s explore another option: abstract factories.

A solution

The abstract factory pattern is described like this:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes.

Here I’ve defined a new abstract factory that produces objects that respond to to_s usefully. The code that uses this system does not change, as it still calls literal and addition as before, except now it calls to_s instead of evaluate.

New strategies are easy to add, but new behavior is not. Again I’ll use the example of inspecting into a String, but this time I’ll make use of the existing run method instead of a new to_s method. Again, just an example.

I recommend reading the paper for more cool examples, such as concurrent computation of the arithmetic system and a DSL for batch processing. They also relate Church encodings to the visitor pattern, and abstract factories to F-algebras. Throughout the paper they talk about static type analysis, too.