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!

« Back to article list

Please do not post this article to Hacker News.

Permission to scrape this site or any of its content, for any purpose, is denied, regardless of your personal beliefs or desire to design a novel opt-out method.