There is no syntax trick in C to achieve method chaining as may be used in some other languages. In C, you would write separate function calls, passing the object pointer to each function:
Widget *w = getWidget();
widgetSetWidth(w, 640);
widgetSetHeight(w, 480);
widgetSetTitle(w, "Sample widget");
widgetSetPosition(w, 0, 0);
The same can be done with method calls in C++ and other OOP languages:
Widget *w = getWidget();
w->SetWidth(640);
w->SetHeight(480);
w->SetTitle("Sample widget");
w->SetPosition(0, 0);
With the above APIs, and assuming each method returns the this
object, the method chaining syntax looks like this:
getWidget()->SetWidth(640)->SetHeight(480)->SetTitle("Sample widget")->SetPosition(0, 0);
Whether this is more readable than the separate statements is a matter of taste and local coding conventions. I personally find it cumbersome and harder to read. There is a small advantage in terms of code generation: the object pointer does not need to be reloaded from a local variable for the next call. This minuscule optimisation hardly justifies the chaining syntax.
Some programmers try and make it more palatable this way:
getWidget()
-> SetWidth(640)
-> SetHeight(480)
-> SetTitle("Sample widget")
-> SetPosition(0, 0);
Again, a matter of taste and coding conventions... But the C equivalent definitely looks awkward:
Widget *w = widgetSetPosition(widgetSetTitle(widgetSetHeight(widgetSetWidth(getWidget(), 640), 480), "Sample widget"), 0, 0);
And there is no easy way to reorganise this chain into some more readable.
Note that some of the most ancien C library functions can be chained too:
const char *hello = "Hello";
const char *world = "World";
char buf[200];
strcpy(buf, hello);
strcat(buf, " ");
strcat(buf, world);
strcat(buf, "\n");
Can be reorganised into:
strcat(strcat(strcat(strcpy(buf, hello), " "), world), "\n");
But a safer and much preferred approach is this:
snprintf(buf, sizeof buf, "%s %s\n", hello, world);
For more information, you might want to read this:
Marco Pivetta (Ocramius): Fluent Interfaces are Evil
Note also that if the C object has function pointer members for these calls, all of the above syntaxes could be used, but the object pointer must still be passed as an argument. The function pointers are usually grouped in a structure to which a pointer is stored in the object, mimicking the implementation of C++ virtual methods, making the syntax slightly heavier:
Widget *w = getWidget();
w->m->SetWidth(w, 640);
w->m->SetHeight(w, 480);
w->m->SetTitle(w, "Sample widget");
w->m->SetPosition(w, 0, 0);
Chaining these is possible too, but for no real gain.
Finally, it should be noted that method chaining does not allow for explicit error propagation. In OOP languages where chaining is idiomatic, exceptions can be thrown to signal errors in a more or less palatable way. In C the idiomatic way to handle errors is to return an error status, which conflicts with returning a pointer to the object.
As a consequence, unless the methods are guaranteed to succeed, it is advisable to not use method chaining and perform iterative tests instead:
Widget *w = getWidget();
if (SetWidth(w, 640)
|| SetHeight(w, 480)
|| SetTitle(w, "Sample widget")
|| SetPosition(w, 0, 0)) {
/* there was an error, handle it gracefully */
}