Dissolving patterns

30 Apr 2011

I forget where I first read about this meme, but I’ve been appreciating it more and more over time:

Once a programming pattern achieves widespread use, languages start to absorb it into their structure.

Object-orientation is a pattern in C, because you have to use a library like gobject to implement virtual method calls, and you have to write code to that library’s conventions. In java, you get virtual method calls as default behavior. It’s not a pattern; it’s part of the language.

Iteration used to be a pattern in java, but by java 5, there was enough syntactic sugar to make iteration seem like a natural part of the language. You don’t have to think about iterating; you can do it with half a line of code. You don’t usually need to think about how to create iterable objects, either, because the standard library has a set of methods to make it easy. It’s become a part of the language.

Another way to look at patterns is that they’re boilerplate you need to add to your code — boilerplate you could avoid (or make a lot smaller) if the pattern was integrated into the language. So as a pattern becomes commonly accepted, it’s more likely to be added as a core feature, and cease to be a pattern at all. I think this is part of the reason that high-level languages are terser than low-level languages: patterns become syntax.

There are two patterns that I think should go away in a scala (or any post-java language) world.

Factories

The factory pattern is used to abstract away object creation, usually so libraries can have functionality injected. For example, a popular HTTP library for java uses a factory to allow clients to replace or augment the socket library:

interface SocketFactory {
  public Socket createSocket();
}

This is a cool feature, because it allows the library to be very configurable, but it ends up creating a lot of boilerplate code when it’s used:

class MySSLSocketFactory {
  public Socket createSocket() {
    return new MySSLSocket();
  }
}
...
Protocol p = new Protocol("https", new MySSLSocketFactory(), 443);

Let’s look at the interface a bit more closely. It’s really just sugar for a single method which takes zero or more parameters and returns a new object. In fact, let me suggest that it’s really just another way of describing… a function! But in higher-level languages, functions are first-class objects, so we could define the factory that way instead:

type SocketFactory = () => Socket

And instead of creating a factory, we can just pass in our function for creating sockets:

val protocol = new Protocol("https", { () => new MySSLSocket() }, 443)

Poof! All the boilerplate is gone. You don’t need a factory because a factory is just a function, and the function is a factory. The pattern is integrated into the language already.

So I propose that the next time you start to write a factory interface, you just use a function instead.

Builders

That probably isn’t very controversial or shocking, but let me go one step further and tackle a tougher pattern: the builder.

Builders are used when an object may have a lot of initial state to configure. For example, if your class constructor has 10 parameters, you probably want to create a builder so that constructing it can be a little more self-documenting, and optional configuration can be omitted.

As immutable objects become more popular, builders are also becoming a popular way to allow multi-step construction in a mutable object before squirting out the final immutable object.

Here’s an example from the android API. There are different code styles, but the most common one seems to be a cascade of method calls, culminating in a final create call:

AlertDialog alert = new AlertDialog.Builder(this)
  .setTitle("Alert!").setMessage("lp on fire!")
  .setNegativeButton("Denial", null)
  .setPositiveButton("Acceptance", null)
  .create();

You have to admit, at least, that it’s a lot better (and easier to understand) than a huge constructor call, which could end up looking something like:

AlertDialog alert = new AlertDialog(this, "Alert!", 0, "lp on fire!", null, null, button1, ...)

Anyway, you’ve probably already guessed what I’m going to say about that create call: It’s a factory function!

But the cascading method calls can be fixed too. What if the builder class was replaced by a configuration class with mutable fields? It might look like this:

class Builder extends (() => AlertDialog) {
  var title: String = ""
  var message: String = ""
  var positiveButton: Option[Button] = None
  ...
  def apply() = ...
}

The builder class is a factory function that generates new AlertDialog objects — that is, it’s a function () => AlertDialog — but it also has a bunch of optional, mutable configuration. Instead of cascading method calls, you can use the constructor to override any fields you want to set:

val builder = new Builder {
  title = "Alert!"
  message = "lp on fire!"
  positiveButton = Some(new Button(...))
}
val alert = builder()

I think this is even easier to read than the builder call. To avoid confusion, I call these classes Config instead of Builder, but they have exactly the same effect: to create a (possibly immutable) object out of mutable configuration.

It looks like having functions as first-class objects lets us integrate at least two patterns into the language, but there are a lot more to work on. For one, the delegator pattern seems to still involve a lot of boilerplate in most languages. So there is more to be done! Onward and upward!

blog comments powered by Disqus
« Back to article list