55

Having chaining implemented on beans is very handy: no need for overloading constructors, mega constructors, factories, and gives you increased readability. I can't think of any downsides, unless you want your object to be immutable, in which case it would not have any setters anyway. So is there a reason why this isn't an OOP convention?

public class DTO {

    private String foo;
    private String bar;

    public String getFoo() {
         return foo;
    }

    public String getBar() {
        return bar;
    }

    public DTO setFoo(String foo) {
        this.foo = foo;
        return this;
    }

    public DTO setBar(String bar) {
        this.bar = bar;
        return this;
    }

}

//...//

DTO dto = new DTO().setFoo("foo").setBar("bar");
muru
  • 142
  • 8
Ben
  • 1,002
  • 2
  • 10
  • 11
  • 35
    Because Java may be the only language where setters aren't an abomination unto man... – Telastyn Feb 02 '16 at 17:43
  • 13
    It's bad style because the return value is not semantically meaningful. It's misleading. The only upside is saving very few keystrokes. – usr Feb 02 '16 at 20:12
  • 65
    This pattern is not uncommon at all. There is even a name for it. It's called [fluent interface](https://en.wikipedia.org/wiki/Fluent_interface). – Philipp Feb 02 '16 at 22:31
  • 9
    You can also abstract this creation in a builder for a more readable result. `myCustomDTO = DTOBuilder.defaultDTO().withFoo("foo").withBar("bar").Build();` I'd do that, so as to not conflict with the general idea that setters are voids. –  Feb 02 '16 at 23:21
  • 10
    @Philipp, while technically you're right, wouldn't say that `new Foo().setBar('bar').setBaz('baz')` feels very "fluent". I mean, sure it could be implemented exactly the same way, but I'd very much expect to read something more like `Foo().barsThe('bar').withThe('baz').andQuuxes('the quux')` – Wayne Werner Feb 03 '16 at 04:00
  • 2
    @Telastyn can you elaborate on that? I'm struggling to see what Java setters do that is so special. – Gusdor Feb 03 '16 at 08:26
  • 4
    This is not the definition of fluent. You can have a clean fluent interface if you return a *new and immutable* object. – usr Feb 03 '16 at 11:47
  • 1
    @gusdor - most languages consider setters on objects (as opposed to Plain Old Data) to be a smell, since it is directly manipulating class state, violating encapsulation/invariants. In languages like C#, setters like this are not idiomatic, since they use `prop = value` sort of syntax, which cannot chain. – Telastyn Feb 03 '16 at 12:56
  • If something weird happens on the chained method line, I will need to debug-jump through all of the methods in order until I find the one who dun' it. – Ceiling Gecko Feb 03 '16 at 14:02
  • 3
    +1 for @AlexM.'s suggestion for a builder. It gives the possibility of an immutable object with most of the flexibility of setters. – Chad Schouggins Feb 03 '16 at 19:35
  • The reason I don't like it, is that you're doing two things: changing your object and as a function: returning an instance of this object. Also you example smells a lot like a constructor, but that depends whether setting foo and bar is optional, because if you don't chain your foo and bar will be null, which may or may not be good. If they're required to be set, this is a bad way. – Pieter B Feb 03 '16 at 22:08
  • @AlexM. It is something that can be solved in Java as follows: `public class Foo {...}` with the setter returning `Foo`, that way Inheritance doesn't break the setters. Also those 'setter' methods, I also prefer to call them 'with' methods. If overloading works fine, then just `Foo with(Bar b) {...}`, otherwise `Foo withBar(Bar b)`. – YoYo Feb 04 '16 at 09:57
  • 1
    @CeilingGecko On debug-jumping - assuming the only difference was the return value of the setters (void vs DTO), don't you still have to go through them anyway, just laid out in separate statements? – Lawrence Feb 04 '16 at 11:18
  • @Lawrence if one statement decides to throw a nasty exception the stacktrace points to the real offender since there is only 1 thing done on the line – masterX244 Feb 04 '16 at 14:12
  • 1
    @masterX244 I've just tried `new X().setA().setB().setC();` in Java with a dummy class X, setA and setC returning X, and setB throwing an exception. The stack trace points to setB. In general, in a chain of function calls with one of them throwing an exception, I'd expect the stack trace to identify that as the 'leaf node' that threw the exception. – Lawrence Feb 04 '16 at 14:21
  • 1
    This pattern is hardly non-OOP. In Smalltalk (OO language written before there ever was a Java),having every instance method return self was standard practice. – PaulMcG Feb 04 '16 at 14:54
  • Nothing forbids you from writing extra constructors or static factories to help you creating value objects. – Olivier Grégoire Feb 04 '16 at 15:13
  • In Swift you don’t use setter methods, but properties and what looks like an assignment operator. Chaining is not syntactically possible. – gnasher729 Aug 21 '22 at 14:34
  • @Telastyn isn't the opposite true? Setters are functions which do *not* manipulate instance state directly; they can apply logic, refuse e.g. IllegalArgumentException and so on. Direct member access on a POJO would be the smell. Did you mix both up, or is there some aspect I didn't get? – foo Feb 04 '23 at 17:23
  • @foo - look at the OP’s example, they are definitely manipulating state directly. Setters as I am using the term is anything like `SetFoo`. By definition, you’re changing the state of Foo… – Telastyn Feb 04 '23 at 23:22
  • @Telastyn - I see the OP doing the Bad Thing, but (a) it's short sample code, (b) doesn't mean it has to be that way. It can be made safe. Whereas direct access to a POJO member never can be made safe. – foo Feb 06 '23 at 15:30
  • @foo - it’s a pojo. If you aren’t providing direct access, then it by definition isn’t a plain old object. – Telastyn Feb 06 '23 at 15:35

7 Answers7

55

So is there a reason why isn't this a OOP convention?

My best guess: because it violates CQS

You've got a command (changing the state of the object) and a query (returning a copy of state -- in this case, the object itself) mixed into the same method. That's not necessarily a problem, but it does violate some of the basic guidelines.

For instance, in C++, std::stack::pop() is a command that returns void, and std::stack::top() is a query that returns a reference to the top element in the stack. Classically, you would like to combine the two, but you can't do that and be exception safe. (Not a problem in Java, because the assignment operator in Java doesn't throw).

If DTO were a value type, you might achieve a similar end with

public DTO setFoo(String foo) {
    return new DTO(foo, this.bar);
}

public DTO setBar(String bar) {
    return new DTO(this.foo, bar);
}

Also, chaining return values are a colossal pain-in-the- when you are dealing with inheritance. See the "Curiously recurring template pattern"

Finally, there's the issue that the default constructor should leave you with an object that is in a valid state. If you must run a bunch of commands to restore the object to a valid state, something has gone Very Wrong.

VoiceOfUnreason
  • 32,131
  • 2
  • 42
  • 79
  • 5
    Finally, a real catain here. Inheritance is the real problem. I think chaining could be a conventional setter for data-representation-objects that are used in composition. – Ben Feb 02 '16 at 17:56
  • 7
    "returning a copy of state from an object" - it doesn't do that. – user253751 Feb 02 '16 at 20:21
  • @Benedictus inheritance is _not_ a problem if this is done correctly, but it does add complexity. You can use the `getSelf()` trick... – Boris the Spider Feb 02 '16 at 21:46
  • 2
    I would argue that the biggest reason for following those guidelines (with some notable exceptions like iterators) is that it makes the code *vastly* easier to reason about. – jpmc26 Feb 02 '16 at 22:27
  • @BoristheSpider: what is this `getSelf()` thing? Is this specific to a particular language? – Matthieu M. Feb 03 '16 at 10:39
  • 5
    @MatthieuM. nope. I mainly speak Java, and it's prevalent there in advanced "fluid" APIs - I'm sure it also exists in other languages. Essentially you make your type _generic_ on a type extending itself. You then add an `abstract` `T getSelf()` method with returns the generic type. Now, instead of returning `this` from your setters, you `return getSelf()` and then any overriding class simply makes the type generic in itself and returns `this` from `getSelf`. This way the setters return the actual type and not the declaring type. – Boris the Spider Feb 03 '16 at 10:42
  • @BoristheSpider: I don't see how it would translate in C++ or Rust... sounds quite specific :x – Matthieu M. Feb 03 '16 at 10:44
  • 1
    @MatthieuM. really? Sounds similar to CRTP for C++ ... – Useless Feb 03 '16 at 12:45
  • @Useless: Ah, it might. Given that we were talking OO I was expecting virtual methods, in which case the derived class can use a more distinct return type (covariance) however the if you have a reference to the base class you cannot call any derived class setter and I was wondering how Java would make it possible :) – Matthieu M. Feb 03 '16 at 13:37
  • 2
    For the record, the reason why std::stack::pop doesn't return the value that popped is because the function is older than move references so it would necessarily have to make a copy to return it, which could be too expensive it you don't plan to use the value. A possible solution would be creating two separate functions, std::stack::pop and std::stack::pop_noreturn, but keeping pop as void and top as returning a value is good enough. – Martín Fixman Feb 03 '16 at 18:32
  • @MatthieuM. the return type of the setter isn't the the `Object` it's the _generic parameter_. i.e. the extending class can specify the return type of the setter - similar to how a class inheriting from a `List` of a specific type would work - it can tell the parent class what the type of `get(int idx)` will be. – Boris the Spider Feb 04 '16 at 14:37
  • @BoristheSpider: Okay, so that's something CRTP could do in C++ indeed `T& set(...) { ...; return static_cast(*this); }`. – Matthieu M. Feb 04 '16 at 17:50
  • 1
    @MatthieuM. that would be the "non type-safe" way of doing it - I think. Usually one would have a method `&T getSelf()` that would be virtual (is that the right term - implemented in the subclass). The setter would `return getSelf()` and the subclass would then `return this`. As this subclass knows its own type - this would be safer. But however you do it, fluent APIs don't have to be broken by inheritance. – Boris the Spider Feb 04 '16 at 17:52
  • @BoristheSpider: In C++, `T& getSelf()` cannot be `virtual` (you cannot mix compile-time and run-time polymorphism). Also, `static_cast` checks at compile-time that `T` inherits from your base, which also helps; you can eliminate the risk of error by using `dynamic_cast` (but it has a performance penalty). – Matthieu M. Feb 04 '16 at 18:00
  • 1
    "You've got a command (changing the state of the object) and a query (returning a copy of state -- in this case, the object itself) mixed into the same method.": If you were using functional objects, a setter would return a new object with one attribute changed. Then a fluent interface like this would be perfectly OK. – Giorgio Feb 04 '16 at 20:27
  • I agree and feel any discussion about fluid interfaces should be clear about whether it is dealing with immutable or mutable objects, because the latter doesn't work so well in my opinion. – LegendLength Jul 15 '17 at 10:33
36
  1. Saving a few keystrokes isn't compelling. It might be nice, but OOP conventions care more about concepts and structures, not keystrokes.

  2. The return value is meaningless.

  3. Even more than being meaningless, the return value is misleading, since users may expect the return value to have meaning. They may expect that it is an "immutable setter"

    public FooHolder {
        public FooHolder withFoo(int foo) {
            /* return a modified COPY of this FooHolder instance */
        }
    }
    

    In reality your setter mutates the object.

  4. It doesn't work well with inheritance.

    public FooHolder {
        public FooHolder setFoo(int foo) {
            ...
        }
    }
    
    public BarHolder extends FooHolder {
        public FooHolder setBar(int bar) {
            ...
        }
    } 
    

    I can write

    new BarHolder().setBar(2).setFoo(1)
    

    but not

    new BarHolder().setFoo(1).setBar(2)
    

For me, #1 through #3 are the important ones. Well-written code is not about pleasantly arranged text. Well-written code is about the fundamental concepts, relationships, and structure. Text is only a outward reflection of code's true meaning.

Paul Draper
  • 5,972
  • 3
  • 22
  • 37
  • 3
    Most of these arguments apply to any fluent/chainable interface, though. – Casey Feb 02 '16 at 22:29
  • @Casey, yes. Builders (i.e. with setters) is the most case I see of chaining. – Paul Draper Feb 02 '16 at 23:33
  • 13
    If you're familiar with the idea of a fluent interface, #3 doesn't apply, since you're likely to suspect a fluent interface from the return type. I also have to disagree with "Well-written code is not about pleasantly arranged text". That's not all it's about, but nicely arranged text is rather important, since it allows the human reader of the program to understand it with less effort. – Michael Shaw Feb 03 '16 at 05:36
  • 3
    Setter chaining is not about pleasantly arranging the text or about saving keystrokes. It's about reducing the number of identifiers. With setter chaining you can create and set up the object in a single expression, which means you might not have to save it in a variable - a variable [you'll have to name](http://martinfowler.com/bliki/TwoHardThings.html), and that will stay there until the end of the scope. – Idan Arye Feb 03 '16 at 13:00
  • @MichaelShaw, yes, if chaining is a convention you're used to, then you'll understand it, by definition. But it still demands some additional time for understanding. For example, [`GetObjectRequest#withBucketName`](http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/model/GetObjectRequest.html#withBucketName(java.lang.String)) returns a `GetObjectRequest`. Is it a new one or a modified one? Conventions are insufficient. Time to look at the docs. – Paul Draper Feb 03 '16 at 13:18
  • @IdanArye, in most languages, you can create arbitrary scopes. E.g. in Java, with `{}`. Naming things is not foreign to OOP. Naming classes, naming methods, naming parameters. – Paul Draper Feb 03 '16 at 13:21
  • 4
    About point #4, it is something that can be solved in Java as follows: `public class Foo {...}` with the setter returning `Foo`. Also those 'setter' methods, I prefer to call them 'with' methods. If overloading works fine, then just `Foo with(Bar b) {...}`, otherwise `Foo withBar(Bar b)`. – YoYo Feb 04 '16 at 09:51
12

I don't think this is an OOP convention, it's more related to the language design and its conventions.

It seems you like to use Java. Java has a JavaBeans specification which specifies the return type of the setter to be void, i.e. it is in conflict with chaining of setters. This spec is widely accepted and implemented in a variety of tools.

Of course you might ask, why isn't chaining part of the specification. I don't know the answer, maybe this pattern just wasn't known/popular at that time.

rsavchenko
  • 103
  • 3
qbd
  • 2,876
  • 1
  • 12
  • 16
  • Yeah, JavaBeans is exactly what I had in mind. – Ben Feb 02 '16 at 17:21
  • I don't think that most applications that use JavaBeans care, but they might (using reflection to grab the methods that are named 'set...', have a single parameter, *and are void return*). Many static analysis programs complain about not checking a return value from a method that returns something and this could be very annoying. –  Feb 02 '16 at 17:33
  • @MichaelT reflective calls to get methods in Java do not specify return type. Calling a method that way returns `Object`, which may result in the singleton of type `Void` being returned if the method specifies `void` as its return type. In other news, apparently "leaving a comment but not voting" is grounds for failing a "first post" audit even if it is a good comment. I blame shog for this. –  Feb 24 '16 at 04:43
8

As other people have said, this is often called a fluent interface.

Normally setters are call passing in variables in response to the logic code in an application; your DTO class is a example of this. Conventional code when setters don’t return anything is normal best for this. Other answers have explained way.

However there are a few cases where fluent interface may be a good solution, these have in common.

  • Constants are mostly passed to the setters
  • Program logic does not change what is passed to the setters.

Setting up configuration, for example fluent-nhibernate

Id(x => x.Id);
Map(x => x.Name)
   .Length(16)
   .Not.Nullable();
HasMany(x => x.Staff)
   .Inverse()
   .Cascade.All();
HasManyToMany(x => x.Products)
   .Cascade.All()
   .Table("StoreProduct");

Setting up test data in unit tests, using special TestDataBulderClasses (Object Mothers)

members = MemberBuilder.CreateList(4)
    .TheFirst(1).With(b => b.WithFirstName("Rob"))
    .TheNext(2).With(b => b.WithFirstName("Poya"))
    .TheNext(1).With(b => b.WithFirstName("Matt"))
    .BuildList(); // Note the "build" method sets everything else to
                  // senible default values so a test only need to define 
                  // what it care about, even if for example a member 
                  // MUST have MembershipId  set

However creating good fluent interface is very hard, so it only worth it when you have lots of “static” setup. Also fluent interface should not be mixed in with “normal” classes; hence the builder pattern is often used.

Glorfindel
  • 3,137
  • 6
  • 25
  • 33
Ian
  • 4,594
  • 18
  • 28
5

I think much of the reason it's not a convention to chain one setter after another is because for those cases it's more typical to see an options object or parameters in a constructor. C# has an initializer syntax as well.

Instead of:

DTO dto = new DTO().setFoo("foo").setBar("bar");

One might write:

(in JS)

var dto = new DTO({foo: "foo", bar: "bar"});

(in C#)

DTO dto = new DTO{Foo = "foo", Bar = "bar"};

(in Java)

DTO dto = new DTO("foo", "bar");

setFoo and setBar are then no longer needed for initialization, and can be used for mutation later.

While chainability is useful in some circumstances, it's important to not try to stuff everything on a single line just for the sake of reducing newline characters.

For example

dto.setFoo("foo").setBar("fizz").setFizz("bar").setBuzz("buzz");

makes it harder to read and understand what's happening. Reformatting to:

dto.setFoo("foo")
    .setBar("fizz")
    .setFizz("bar")
    .setBuzz("buzz");

Is much easier to understand, and makes the "mistake" in the first version more obvious. Once you've refactored code to that format, there's no real advantage over:

dto.setFoo("foo");
dto.setBar("bar");
dto.setFizz("fizz");
dto.setBuzz("buzz");
zzzzBov
  • 5,794
  • 1
  • 27
  • 28
  • 3
    1. I really cannot agree with the readability issue, adding instance before each call is not making it clearer at all. 2. The initialisation patterns you showed with js and C# has nothing to do with constructors: what you did in js is passed a single argument, and what you did in C# is a syntax shugar that calls geters and setters behind the scenes, and java does not have the geter-setter shugar like C# does. – Ben Feb 02 '16 at 17:48
  • 1
    @Benedictus, I was showing various different ways that OOP languages handle this issue without chaining. The point wasn't to provide identical code, the point was to show alternatives that make chaining unnecessary. – zzzzBov Feb 02 '16 at 18:42
  • 2
    "adding instance before each call is not making it clearer at all" I never claimed that adding the instance before each call made anything clearer, I just said that it was relatively equivalent. – zzzzBov Feb 02 '16 at 18:43
  • 1
    VB.NET also has a usable "With" keyword which creates a compiler-temporary reference so that e.g. [using `/` to represents line break] `With Foo(1234) / .x = 23 / .y = 47` would be equivalent to `Dim temp=Foo(1234) / temp.x = 23 / temp.y = 47`. Such syntax does not creating ambiguity since `.x` by itself can have no meaning other than to bind to the immediately surrounding "With" statement [if there is none, or the object there has no member `x`, then `.x` is meaningless]. Oracle hasn't included anything like that in Java, but such a construct would fit smoothly in the language. – supercat Feb 03 '16 at 21:15
5

That technique is actually used in the Builder pattern.

x = ObjectBuilder()
        .foo(5)
        .bar(6);

However, in general it is avoided because it is ambiguous. It is not obvious whether the return value is the object (so you can call other setters), or if the return object is the value that was just assigned (also a common pattern). Accordingly, the Principle of Least Surprise suggests you shouldn't try to assume the user wants to see one solution or the other, unless its fundamental to the object's design.

Cort Ammon
  • 10,840
  • 3
  • 23
  • 32
  • 7
    The difference is that, when using the builder pattern, you are usually writing a write-only object (the Builder) that eventually constructs a read-only (immutable) object (whatever class you're building). In that regard, having a long chain of method calls is *desirable* because it can be used as a single expression. – Darkhogg Feb 03 '16 at 13:32
  • "or if the return object is the value that was just assigned" I hate that, if I want to keep the value I just passed in I'll put it in a variable first. It can be useful to obtain the value that was _previously_ assigned, though (some container interfaces do this, I believe). – JAB Feb 04 '16 at 15:21
  • @JAB I agree, I'm not such a fan of that notation, but it has its places. The one that comes to mind is `Obj* x = doSomethingToObjAndReturnIt(new Obj(1, 2, 3));` I think it also gained popularity because it mirrors `a = b = c = d`, though I'm not convinced that popularity was well founded. I have seen the one you mention, returning the previous value, in some atomic operation libraries. Moral of the story? It's even more confusing than I made it sound =) – Cort Ammon Feb 04 '16 at 16:11
  • I believe that academics get a little pedantic: There's nothing inherently wrong with the idiom. It's tremendously useful in adding clarity in certain cases. Take the following text formatting class for example that indents every line of a string and draws an ascii-art box around it `new BetterText(string).indent(4).box().print();`. In that case, I've bypassed a bunch of gobbledygook and taken a string, indented it, boxed it, and output it. You might even want a duplication method within the cascade (such as, say, `.copy()`) to allow all following actions to no longer modify the original. – tgm1024--Monica was mistreated Dec 03 '18 at 16:34
2

This is more of a comment than an answer, but I can't comment, so...

just wanted to mention that this question surprised me because I don't see this as uncommon at all. Actually, in my environment of work (web developer) is very very common.

For instance, this is how Symfony's doctrine:generate:entities command auto-generates all setters, by default.

jQuery kinda chains most of its methods in a very similar way.

xDaizu
  • 247
  • 2
  • 8
  • Js is an abomination – Ben Feb 04 '16 at 12:08
  • @Benedictus I'd say PHP is the bigger abomination. JavaScript is a perfectly fine language and has become quite nice with the inclusion of ES6 features (though I'm sure some people still prefer CoffeeScript or variants; personally, I'm not a fan of how CoffeeScript handles variable scoping as it checks outer scope first rather than treating variables assigned to in local scope as local unless explicitly indicated as nonlocal/global the way Python does it). – JAB Feb 04 '16 at 15:25
  • @Benedictus I concur with `JAB`. In my college years I used to look down at JS as an abomination wanna-be scripting language, but after working a couple of years with it, and learning the *RIGHT* way of using it, I've come to... actually **love** it. And I think that with ES6 it will become a really *mature* language. But, what makes me turn my head is... **what does my answer have to do with JS in the first place?** ^^U – xDaizu Feb 08 '16 at 09:10
  • I actually worked a couple of years with js and can say that i've learned it's ways. Nevertheless I see this language as nothing more but a mistake. But I agree, Php is much worse. – Ben Feb 08 '16 at 09:48
  • @Benedictus I understand your position and I respect it. I still like it, though. Sure, it has its quirks and perks (which language doesn't?) but it's steadily stepping in the right direction. But... **I actually don't like it so much that I need to defend it.** I don't gain anything from people loving or hating it... hahaha Also, **this is no place for that, my answer wasnt even about JS at all.** – xDaizu Feb 08 '16 at 10:30
  • While JS is being repulsive in it's structural sence, it's not really the quirks and perks that I feel pissed about. The position ECMA script took in the browsers is simply grotesque: something that's supposed to be a bytcode to execute commands for the browser is actually a fully-featured high level language. While keeping bytcodes compatible in different envirnoments is different, the javascript is a true nightmare in compatibility and flexibility sense. – Ben Feb 10 '16 at 13:21
  • Yeah, and back to the answer, why did I picked on JS? It's simply because I don't think JS's paradigm is compatible to fit as example for this pattern (have you ever had to write a setter in js prototype?). And you're talking about frameworks, not coding practices. – Ben Feb 10 '16 at 13:22
  • @Benedictus I didn't talk about JS. At most, I talked about a *very common very renowned* **library**'s convention (jQuery). And I added *kinda*. My main example was on PHP (Symfony/Doctrine). And yes, I'm talking about frameworks because they extend their coding practices, for better or worse (the benefits of these practices is up to debate, of course, but the fact that they do extend them, it is not), **especially** when they are an integral part of their ***autocomplete the code of the class*** functionality... so it's *kinda* relevant imho. – xDaizu Feb 10 '16 at 15:11
  • @Benedictus ...about **JS**'s structural bytcode *watchayacallit*... **I couldn't shrug harder**. Sorry, don't take this as an insult or disrespect, but you are wasting your knowledge (and/or angst) on this particular comment section. I don't care about the thingies that make the languages tick; and my answer isn't relevant enough to *reach other people*, so... – xDaizu Feb 10 '16 at 15:16