Whole and part
Remember this proverb, "the whole is greater than the sum of the parts"? If one individual event is combined into an interacting whole, the result will be much greater than the sum of the individual's actions.
Procedures are the same. As new methods are added to the program, the possible control flow of the entire program increases rapidly. For large programs, the situation will soon be out of control. Like an absurd and incredible trick, sometimes the end result you get is not the direction you expect--something similar to what you might encounter when overloading a method or overriding a method.
Broken Dispatch Error mode
One of the most powerful features of object-oriented languages is inheritance polymorphism. This feature allows us to overload and override methods based on parameter types. But, like other powerful tools, this feature introduces new dangers.
While Java programmers can quickly learn to manage the rules of which method will be invoked in a call, it is easy to do this in a large program: overloading a method in a class, with the result that code that was previously available to run in another class was interrupted. Such a mistake is in line with what I call the broken Dispatch model.
The pattern can be described as follows:
The arguments passed to an overloaded method, such as Foo, are passed to another method, such as Goo, which supports a wider range of parameter types.
Goo then invokes foo with these parameters.
However, because of the wider static type of these parameters within the goo, the wrong version of method Foo may be invoked.
Errors like this are difficult to diagnose, because it is possible to simply add a new method (rather than modifying an existing method) to introduce an error. Also, the program may continue to execute for a considerable period of time before the problem is discovered.
Symptoms
To illustrate the nature of this pattern, let's take a look at the example code below, which is written to implement the immutable list in the "Empty flag error pattern" of my previous article.
Listing 1. Implementing an immutable List
interface List {
public Object getFirst();
public List getRest();
}
class Empty implements List {
public Object getFirst() { throw new NoSuchElementException(); }
public List getRest() { throw new NoSuchElementException(); }
public boolean equals(Object that) {
return this.getClass() == that.getClass();
}
}
class Cons implements List {
Object first;
List rest;
Cons(Object _first) {
this.first = _first;
this.rest = new Empty();
}
Cons(Object _first, List _rest) {
this.first = _first;
this.rest = _rest;
}
public Object getFirst() { return this.first; }
public List getRest() { return this.rest; }
...
}