8

I have a class that has three methods A(), B() and C(). Those methods modify the own instance.

While the methods have to return an instance when the instance is a separate copy (just as Clone()), I got a free choice to return void or the same instance (return this;) when modifying the same instance in the method and not returning any other value.

When deciding for returning the same modified instance, I can do neat method chains like obj.A().B().C();.

Would this be the only reason for doing so?

Is it even okay to modify the own instance and return it, too? Or should it only return a copy and leave the original object as before? Because when returning the same modified instance the user would maybe admit the returned value is a copy, otherwise it would not be returned? If it's okay, what's the best way to clarify such things on the method?

6

When to use chaining

Function chaining is mostly popular with languages where an IDE with auto-complete is common place. For example, almost all C# developers use Visual Studio. Therefore, if you're developing with C# adding chaining to your methods can be a time saver for users of that class because Visual Studio will assist you in building the chain.

On the other hand, languages like PHP that are highly dynamic in nature and often don't have auto-complete support in IDEs will see fewer classes that support chaining. Chaining will only be appropriate when correct phpDocs are employed to expose the chainable methods.

What is chaining?

Given a class named Foo the following two methods are both chainable.

function what() { return this; }
function when() { return new Foo(this); }

The fact that one is a reference to the current instance, and one creates a new instance doesn't change that these are chainable methods.

There is no gold rule that a chainable method must only reference the current object. Infact, chainable methods can be across two different classes. For example;

class B { function When() { return true; } };
class A { function What() { return new B(); } };

var a = new A();
var x = a.What().When();

There is no reference to this in any of the above example. The code a.What().When() is an example of a chaining. What's interesting is that the class type B is never assigned to a variable.

A method is chained when it's return value becomes used as the next component of an expression.

Here are some more example

 // return value never assigned.
 myFile.Open("something.txt").Write("stuff").Close();

// two chains used in expression
int x = a.X().Y() * b.X().Y();

// a chain that creates new strings
string name = str.Substring(1,10).Trim().ToUpperCase();

When to use this and new(this)

Strings in most languages are immutable. So chaining method calls always results in new strings being created. Where as an object like StringBuilder can be modified.

Consistency is best practice.

If you have methods that modify the state of an object and return this, then don't mix in methods that return new instances. Instead, create a specific method called Clone() that will do this explicitly.

 var x  = a.Foo().Boo().Clone().Foo();

That is a lot clearer as to what is going on inside a.

The Step Outside And Back Trick

I call this the step out and back trick, because it solves a lot of common problems related to chaining. It basically means that you step out of the original class into a new temporary class and then back to the original class.

The temporary class exists only to provide special features to the original class, but only under special conditions.

There are often times when a chain needs to change state, but class A can not represent all of those possible states. So during a chain a new class is introduced that contains a reference back to A. This allows the programmer to step into a state and back to A.

Here is my example, let the special state be known as B.

class A {
    function Foo() { return this; }
    function Boo() { return this; }
    function Change() return new B(this); }
}

class B {
    var _a;
    function (A) { _a = A; }
    function What() { return this; }
    function When() { return this; }
    function End() { return _a; }
}

var a = new A();
a.Foo().Change().What().When().End().Boo();

Now that is a very simple example. If you wanted to have more control, then B could return to a new super-type of A that has different methods.

  • 3
    I really don't understand why you recommend method chaining depending solely on Intellisense-like autocomplete support. Method chains or fluent interfaces are an API design pattern for any OOP language; the only thing that autocomplete does is preventing typos and type errors. – amon Aug 19 '14 at 15:25
  • @amon you misread what I said. I said it's more popular when intellisense is common for a language. I never said it was depended upon the feature. – Reactgular Aug 19 '14 at 15:38
  • 3
    While this answer helps me a lot to understand the possibilities of chaining, I still lack on the decision when to use chaining at all. Sure, consistency is the best. However, I'm refering to the case when I modify my object in the function and return this. How can I help the users of my libraries to handle and understand this situation? (Allowing them to chain methods, even when it's not required, would this really be okay? Or should I only stick to one way, require changing at all?) – modiX Sep 2 '14 at 7:12
  • @modiX if my answer is correct, then please accept it as the answer. The other stuff you're seeking are opinions on how to use chaining, and there is no right/wrong answer for that. That really is up to you to decide. Maybe you are worrying too much about small details? – Reactgular Sep 2 '14 at 15:56
2

Those methods modify the own instance.

Depending on the language, having methods that return void/unit and modify their instance or parameters is non-idiomatic. Even in languages that used to do that more (C#, C++), it is going out of fashion with the shift towards more functional style programming (immutable objects, pure functions). But let's assume there's a good reason for now.

Would this be the only reason for doing so?

For certain behaviors (think x++) it is expected that the operation returns the result, even though it modifies the variable. But that's largely the only reason to do it on your own.

Is it even okay to modify the own instance and return it, too? Or should it only return a copy and leave the original object as before? Because when return the same modified instance the user would maybe admit the returned value is a copy, otherwise it would not be returned? If it's okay, what's the best way to clarify such things on the method?

It depends.

In languages where copy/new and return is common (C# LINQ and strings) then returning the same reference would be confusing. In languages where modify and return is common (some C++ libraries) then copying would be confusing.

Making the signature unambiguous (by returning void or using language constructs like properties) would be the best way to clarify. After that, making the name clear like SetFoo to show that you're modifying the existing instance is good. But the key is to maintain the idioms of the language/library you're working with.

  • Thx for your answer. I'm mainly working with the .NET framework, and by your answer it's full of non-idiomatic things. While things like LINQ methods return a new copy of the original after appending operations etc. things like the Clear() or Add() of any collection type will modify the same instance and return void. In both cases you say it would be confusing... – modiX Aug 19 '14 at 14:08
  • @modix - LINQ does not return a copy while appending operations. – Telastyn Aug 19 '14 at 14:11
  • Why I can do obj = myCollection.Where(x => x.MyProperty > 0).OrderBy(x => x.MyProperty); then? Where() returns a new collection object. OrderBy() even returns a different collection object, because the content is ordered. – modiX Aug 19 '14 at 14:17
  • @modix - They return new objects that implement IEnumerable, but to be clear, they are not copies, and they are not collections (except for ToList, ToArray, etc.) . – Telastyn Aug 19 '14 at 14:20
  • This is right, they are not copies, furthermore they are new objects, indeed. Also by saying collection I was referencing to objects you can count through (objects that hold more than one object in a any kind of array), not to classes that inherit from ICollection. My bad. – modiX Aug 19 '14 at 14:28
0

(I assumed C++ as your programming-language)

For me this is mostly a readability aspect. If A, B, C are modifiers, especially if this is a temporary object passed as a parameter to some function, e.g.

do_something(
      CPerson('name').age(24).height(160).weight(70)
      );

compared to

{
   CPerson person('name');
   person.set_age(24);
   person.set_height(160);
   person.set_weight(70);
   do_something(person);
}

Regrading if it's ok to return a reference to the modified instance, I'd say yes, and point you for example to the stream operators '>>' and '<<' (http://www.cprogramming.com/tutorial/operator_overloading.html)

  • 1
    You assumed wrong, it's C#. However I want my question to be more common. – modiX Aug 19 '14 at 14:09
  • Sure, could have been Java also, but that was a minor point just to place my example with the operators into context. The essence was that it boils down to readability, which is influenced by the reader's expectations and background, which themselves are influenced by the usual practices in the particular language/frameworks one is dealing with -- as the other answers have also pointed out. – AdrianI Aug 20 '14 at 9:42
0

You could also do the method chaining thing with copy return rather than modify return.

A good C# example is string.Replace(a,b) which doesn't change the string on which it was invoked but instead returns a new string allowing you to chain merrily away.

  • Yes, I know. But I did not want to refer to this case, as I have to use this case when I don't want to edit the own instance, anyways. However, thanks for pointing that out. – modiX Aug 19 '14 at 14:18
  • Per other answers, consistency of semantics is important. Since you can be consistent with copy return and you can't be consistent with modify return (because you can't do it with immutable objects) then I would say the answer to your question is don't use copy return. – Peter Wone Aug 20 '14 at 3:00

protected by gnat Jun 30 '17 at 9:43

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.