Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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");
share|improve this question
31  
Because Java may be the only language where setters aren't an abomination unto man... – Telastyn Feb 2 at 17:43
11  
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 2 at 20:12
54  
This pattern is not uncommon at all. There is even a name for it. It's called fluent interface. – Philipp Feb 2 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. – user52800 Feb 2 at 23:21
8  
@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 3 at 4:00
up vote 45 down vote accepted

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.

share|improve this answer
3  
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. – Benedictus Feb 2 at 17:56
6  
"returning a copy of state from an object" - it doesn't do that. – immibis Feb 2 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 2 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 2 at 22:27
1  
@MatthieuM. really? Sounds similar to CRTP for C++ ... – Useless Feb 3 at 12:45
  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.

share|improve this answer
2  
Most of these arguments apply to any fluent/chainable interface, though. – Casey Feb 2 at 22:29
    
@Casey, yes. Builders (i.e. with setters) is the most case I see of chaining. – Paul Draper Feb 2 at 23:33
9  
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 3 at 5:36
1  
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, and that will stay there until the end of the scope. – Idan Arye Feb 3 at 13:00
2  
About point #4, it is something that can be solved in Java as follows: public class Foo<T extends Foo> {...} with the setter returning Foo<T>. Also those 'setter' methods, I prefer to call them 'with' methods. If overloading works fine, then just Foo<T> with(Bar b) {...}, otherwise Foo<T> withBar(Bar b). – YoYo Feb 4 at 9:51

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.

share|improve this answer
    
Yeah, JavaBeans is exactly what I had in mind. – Benedictus Feb 2 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. – user40980 Feb 2 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. – Snowman Feb 24 at 4:43

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.

share|improve this answer

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");
share|improve this answer
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. – Benedictus Feb 2 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 2 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 2 at 18:43
    
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 3 at 21:15

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.

share|improve this answer
5  
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 3 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 4 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 4 at 16:11

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.

share|improve this answer
    
Js is an abomination – Benedictus Feb 4 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 4 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 8 at 9: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. – Benedictus Feb 8 at 9: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 8 at 10:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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