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!