50

I came across something like this in an open-source project. Methods that modify instance attributes return a reference to the instance. What is the purpose of this construct?

class Foo(object):

  def __init__(self):
    self.myattr = 0

  def bar(self):
    self.myattr += 1
    return self
2
  • 2
    And this is how pretty much all of jQuery is written. Nearly every function returns a jQuery object
    – CaffGeek
    Dec 23, 2010 at 22:26
  • 11
    Why wouldn't you trust code written like that?
    – sepp2k
    Dec 23, 2010 at 23:29

5 Answers 5

69

It's to allow chaining.

For example:

var Car = function () {
    return {
        gas : 0,
        miles : 0,
        drive : function (d) {
            this.miles += d;
            this.gas -= d;
            return this;
        },
        fill : function (g) {
            this.gas += g;
            return this;
        },
    };
}

Now you can say:

var c = Car();
c.fill(100).drive(50);
c.miles => 50;
c.gas => 50;
2
  • 22
    for the record, this kind of chaining is generally seen on code with fluent interface.
    – Lie Ryan
    Oct 10, 2012 at 5:24
  • among the few times I upvote an answer in another language!
    – pcko1
    Feb 10, 2020 at 10:00
11

As @Lie Ryan and @Frank Shearar mention, that's called a "fluent interface" but that pattern has been around for a really long time.

The controversial part of that pattern is that in OO, you have mutable state, so a void method has a kind of implied return value of this -- that is, the object with updated state is kind of the return value.

So in an OO language with mutable state, these two are more or less equivalent:

a.doA()
a.doB()
a.doC()

...as opposed to

a.doA().doB().doC()

So I've heard people in the past resist fluent interfaces because they like the first form. Another name I've heard for "fluent interface" is "train wreck" ;)

I say "more or less equivalent", though, because fluent interfaces add a wrinkle. They don't have to "return this". They can "return new". That's a way of attaining immutable objects in OO.

So you could have a class A that does (pseudocode)

function doA():
    return new A(value + 1)

function doB():
    return new A(value * 2)

function doC():
    return new A(sqrt(value))

Now, each method returns a brand new object, leaving the initial object unchanged. And that's a way of getting into immutable objects without really changing much in your code.

3
  • Ok but if your methods return new(...), that would leak memory.
    – smci
    Jul 17, 2018 at 23:02
  • 1
    @smci That would depend heavily on the language, implementation, and usage. Sure, if it's C++, you'll likely be leaking memory all over the place. But this would all be trivially cleaned up by a language with a garbage collector. Some implementations (with or without GC) may even detect when one of those new objects aren't used and just not actually allocate anything.
    – 8bittree
    Jul 19, 2018 at 20:22
  • @8bittree: we're talking about Python, this question was tagged Python 8 years ago. Python GC is not great so best not to leak memory in the first place. Calling __init__ repeatedly introduces overhead too.
    – smci
    Jul 20, 2018 at 21:15
8

Most language are aware of the 'return self' idiom, and ignore it if it is not used in a line. However it is notable that in Python, functions return None by default.

When I was in CS school my instructor made a huge deal about the difference between functions, procedures, routines, and methods; many hand-cramping essay questions were ground out with mechanical pencils getting hot in my hands about all that.

Suffice it to say, returning self is the definitive OO way to craft class methods, but Python allows for multiple return values, tuples, lists, objects, primitives, or None.

Chaining, as they put it, is merely putting the answer to the last operation into the next, and the runtime of Python can optimize that kind of thing. List comprehensions are a built-in form of this. (Very powerful!)

So in Python it is not so important that every method or function return things, which is why the default is None.

There is a school of thought that every action in a program should report its success, failure, or result back to its invoking context or object, but then were not talking DOD ADA Requirements here. If you need to get feedback from a method, go ahead, or not, but try to be consistent about it.

If a method can fail, it should return success or failure or raise an exception to be handled.

One caveat is that if you use the return self idiom, Python will allow you to assign all your methods to variables and you might think you are getting a data result or a list when you are actually getting the object.

Type-restrictive languages scream and yell and break when you try to do this, but interpreted ones (Python, Lua, Lisp) are much more dynamic.

5

In Smalltalk, every method that doesn't explicitly return something, has an implicit "return self".

That's because (a) having every method return something makes the computing model more uniform and (b) it's very useful having methods return self. Josh K gives a nice example.

2
  • Interesting ... in Python, every method that doesn't explicitly return something, has an implicit "return None".
    – Job
    Dec 24, 2010 at 2:36
  • looks like: smalltalk >> python. I've done zero smalltalk and years of python. Aug 9 at 18:36
2

Pros of returning an object (return self)

  • Example:

    print(foo.modify1().modify2())
    
    # instaed of
    foo.modify1()
    foo.modify2()
    print(foo)
    
  • More popular style in programming community (I think).

Pros of mutating an object (no return self)

  • Ability to use return for other purposes.
  • Guido van Rossum approves of this style (I disagree with his argument).
  • More popular style in Python community (I think).
  • Default (less source code).
7
  • 1
    The Guido arguement is compelling to me. Particular the part where he talks about "the reader must be intimately familiar with each of the methods" I.e. It forces you need to determine if this a self chain or and output chain or a combo before you understand what you have at the end of the chain
    – Nath
    Dec 9, 2016 at 20:40
  • @Nat How string processing operations fundamentally differ from the rest of the operations?
    – xged
    Dec 9, 2016 at 21:59
  • The difference is that the string case your are generating a new completely different object each time. I.e. Not modifying the item in place. it's clear that the existing object isn't being modified. In a language where return self is implicit the opposite is true but the mixed environment seems problematic
    – Nath
    Dec 9, 2016 at 22:15
  • @Matt I just remembered that Python strings are immutable. That fully answers my question.
    – xged
    Dec 9, 2016 at 22:23
  • 1
    @Matt "it's clear that the existing object isn't being modified" - it is not clear just from looking though.
    – xged
    Dec 9, 2016 at 22:24

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