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
smci
  • 139
nate c
  • 797

5 Answers5

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;
Josh K
  • 23,029
  • 10
  • 67
  • 100
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.

sea-rob
  • 6,911
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.

Darknight
  • 12,159
Chris Reid
  • 265
  • 2
  • 3
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.

Frank Shearar
  • 16,751
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).
xged
  • 141