Complex objects often have state that needs to be initialized with possibly many constructor parameters. Defining object initialization with a large number of constructor parameters can ensure that an object is always instantiated in a complete state: The constructor implementation can check for each parameter and raise an exception if an initialization condition is unsatisfied.
However, working with many constructor parameters can be difficult and error prone, because it's easy to mix up the order of parameter values.
Telescoping constructors, to use Josh Bloch's term, are one solution to that problem, where a developer defines one constructor with all required parameter values, and then additional constructors with the optional values.
Other solutions to the lengthy constructor problem are the traditional JavaBeans-style setter and getter methods, as well as the builder pattern. In a recent blog post, Type-safe Builder Pattern in Scala, Rafael de F. Ferreira explains the problems with these approaches, and shows how Scala's extensible type system can provide a more type-safe builder:
It might seem that we just moved the huge constructor mess from one place (clients) to another (the builder). And yes, that is exactly what we did. I guess that is the very definition of encapsulation, sweeping the dirt under the rug and keeping the rug well hidden. On the other hand, we haven't gained all the much from this "functionalization" of our builder; the main failure mode is still present. That is, having clients forget to set mandatory information, which is a particular concern since we obviously can't fully trust the sobriety of said clients. Ideally the type system would prevent this problem, refusing to typecheck a call to build() when any of the non-optional fields aren't set...
In the brief article, Ferreira goes through a full example of using Scala's type system to affect a better builder implementation:
We would begin with an interface VoidBuilder having all our withFoo() methods but no build() method, and a call to, say, withMode() would return another interface (maybe BuilderWithMode()), and so on, until we call the last withBar() for a mandatory Bar, which would return an interface that finally has the build() method. This technique works, but it requires a metric buttload of code — for n mandatory fields 2n interfaces should be created. This could be automated via code generation, but there is no need for such heroic efforts, we can make the typesystem work in our favor by applying some generics magic...
Do you agree with Ferreira's conclusion that Scala's type system can lead to a better and safer builder implementation?
> Seems like an awful lot of work to do what three runtime > assertions in the build() method can do.
There are advantages to receiving compiler errors rather than just having things fail at runtime. If I'm reading the article right, the solution provides the former.