Method Chaining

It is nothing sophisticated, just a fix for a small annoyance when writing code in object-oriented languages.

In object-oriented languages (very simply said) each command has two parts: who should do it, and what should be done. This is usually fine, but sometimes we have to give many commands to the same object.

Imagine a simple application in a fictional programming language. We have two buttons that do some important things with the data (let's call those important things simply "Function 1" and "Function 2"), plus two standard buttons "OK" and "Cancel". You will probably agree that most dialog windows are more complicated. Anyway, just look at that code...

dialog.setWidth(800);
dialog.setHeight(600);
Button function1 = new Button();
function1.setCoordinateX(330);
function1.setCoordinateY(260);
function1.setWidth(140);
function1.setHeight(20);
function1.setTitle("Function 1");
function1.setFunctionOnClick(callFunction1);
Button function2 = new Button();
function1.setCoordinateX(330);
function2.setCoordinateY(290);
function2.setWidth(140);
function2.setHeight(20);
function2.setTitle("Function 2");
function2.setFunctionOnClick(callFunction2);
Button okay = new Button();
okay.setCoordinateX(620);
okay.setCoordinateY(570);
okay.setWidth(80);
okay.setHeight(20);
okay.setTitle("OK");
okay.setFunctionOnClick(saveDataAndCloseDialog);
Button cancel = new Button();
cancel.setCoordinateX(710);
cancel.setCoordinateY(570);
cancel.setWidth(80);
cancel.setHeight(20);
cancel.setTitle("Cancel");
cancel.setFunctionOnClick(closeDialog);

You will probably agree that this code is difficult to read. And it does not do anything complicated. In addition, this code contains one error; try to find it in that heap of letters.

What to do with it?

Of course, in this specific situation, there are many things that could be improved. We could join methods "setCoordinateX(x)" and "setCoordinateY(y)" to one method "setCoordinates(x, y)"; and similarly "setWidth(width)" and "setHeight(height)" to "setSize(width, height)"; and then we would have slightly less commands. We could use the fact that all buttons have the same height. We could make a graphical editor, where we would just draw the buttons and save them.

But for a moment let's forget that it is about buttons. (It could also be an e-mail, where we need to set the sender, receiver, title, message body, digital signature, etc.) Let's focus on the fact that we call multiple methods of the same object in a row. Also, these methods don't return values. They look like this:

method Button.setCoordinateX(x) {
  this.coordinateX = x;
}

Let's change these methods from not returning a value to returning the original object. We do not have to change the original program yet, because the unused return value is simply ignored.

method Button.setCoordinateX(x) {
  this.coordinateX = x;
  return this;
}

Now we can modify the original program so that when multiple methods of the same object are called, we write the name of the object only at the first call. In every following call we will use the fact that the previous method returned the same object, so we only need to write a dot and the following command. Please note that also the constructor returns the object. Therefore:

dialog.setWidth(800)
      .setHeight(600);
Button function1 = new Button()
  .setCoordinateX(330)
  .setCoordinateY(260)
  .setWidth(140)
  .setHeight(20)
  .setTitle("Function 1")
  .setFunctionOnClick(callFunction1);
Button function2 = new Button()
  .setCoordinateX(330)
  .setCoordinateY(290)
  .setWidth(140)
  .setHeight(20)
  .setTitle("Function 2")
  .setFunctionOnClick(callFunction2);
Button okay = new Button()
  .setCoordinateX(620)
  .setCoordinateY(570)
  .setWidth(80)
  .setHeight(20)
  .setTitle("OK")
  .setFunctionOnClick(saveDataAndCloseDialog);
Button cancel = new Button()
  .setCoordinateX(710)
  .setCoordinateY(570)
  .setWidth(80)
  .setHeight(20)
  .setTitle("Cancel")
  .setFunctionOnClick(closeDialog);

The new program is more legible than the old one. And you cannot make the same mistake that was in the original program. (If you did not find it, it consisted of writing "function1" in one of the calls that were supposed to be for "function2". This kind of mistake can happen easily when writing or copying a part of code, and in this case it cannot be discovered automatically.) Notice how the semicolons disappeared from the ends of many lines; those line are now one chained command.

Summary

We can use method chaining when:

  • we often call a few methods of the same object in a row;
  • those methods do no need to return a meaningful result.

We cannot use method chaining when the method returns a meaningful value. For example the method for setting the X coordinate does not need to return a value, but a method for getting the X coordinate returns a value: the X coordinate of the given button. So it cannot return both the X coordinate and the button itself.

In some cases even the setter methods return a result; for example whether the given value was set successfully. But in such case it would be better to signal a failure using an exception, if the programming language allows it.

As with all the programming techniques, also method chaining should be used soberly. You don't have to rewrite all your methods which did not return a value. Just do it when it is meaningful; when the given methods are called often, and often many of them for the same object.

Some programming languages, such as Smalltalk, provide method chaining automatically; if you do not specify a return value, the method automatically returns the given object. Other programming languages (JavaScript) automatically return an undefined value. Yet in other languages (Java) the return value must be written explicitly in every method. Find out what are the rules for your programming language.

viliam@bur.sk