views:

465

answers:

8

Is it good to have all the setter functions return a reference to the object in c++?

A: 

I would not think so. Typically, you think of 'setter' object as doing just that.

Besides, if you just set the object, dont you have a pointer to it anyway?

Shane C. Mason
+16  A: 

It's a usable enough pattern if there's a lot of things that need to be set on an object.

 class Foo
 {
      int x, y, z;
 public:
      Foo &SetX(int x_) { x = x_;  return *this; }
      Foo &SetY(int y_) { y = y_;  return *this; }
      Foo &SetZ(int z_) { z = z_;  return *this; }
 };

 int main()
 {
      Foo foo;
      foo.SetX(1).SetY(2).SetZ(3);
 }

This pattern replaces a constructor that takes three ints:

 int main()
 {
      Foo foo(1, 2, 3); // Less self-explanatory than the above version.
 }

It's useful if you have a number of values that don't always need to be set.

For reference, a more complete example of this sort of technique is refered to as the "Named Parameter Idiom" in the C++ FAQ Lite.

Of course, if you're using this for named parameters, you might want to take a look at boost::parameter. Or you might not...

Eclipse
I've been intrigued by this technique lately. It'll be interesting to see if anybody comes up with any drawbacks.
Fred Larson
Interesting. I had not considered that as an alternative to complex constructors. This technique could cut down on a high number of constructor overloads.
Brian Ensink
There are some things you can't do with this that you can do with constructors (e.g. initializing consts and references)
Eclipse
Josh, you can initialize those with chaining style as well. It's known as a "fluent" API. An example would be "Foo const foo = Foo::build.x(1).y(2).z(3);". This stuff is getting especially popular in C# these days.
@Iraimbilanja - see the named parameter idiom link for how that's done in C++. I was just saying that this simple version has some drawbacks.
Eclipse
+2  A: 

Not all the setters, but some of them could return reference to object to be useful.

kind of

a.SetValues(object)(2)(3)(5)("Hello")(1.4);

I used this once long time ago to build SQL expression builder which handles all the Escapes problems and other things.

SqlBuilder builder;

builder.select( column1 )( column2 )( column3 ).
    where( "=" )( column1, value1 )
                ( column2, value2 ).
    where( ">" )( column3, 100 ).
    from( table1 )( "table2" )( "table3" );

I wasn't able to reproduce sources in 10 minutes. So implementation is behind the curtains.

Mykola Golubyev
I have done similar stuff for constructing XML documents in C++. The question here though seems to be about general property setters.
James Dean
+10  A: 

You can return a reference to this if you want to chain setter function calls together like this:

obj.SetCount(10).SetName("Bob").SetColor(0x223344).SetWidth(35);

Personally I think that code is harder to read than the alternative:

obj.SetCount(10);
obj.SetName("Bob");
obj.SetColor(0x223344);
obj.SetWidth(35);
Brian Ensink
It's a question of layout. You can just write the first part like the second, just omitting obj. on everything but the first and ; on everything but the last. IMHO, it's as readable then.
Torsten Marek
+2  A: 

If your motivation is related to chaining (e.g. Brian Ensink's suggestion), I would offer two comments:

1. If you find yourself frequently settings many things at once, that may mean you should produce a struct or class which holds all of these settings so that they can all be passed at once. The next step might be to use this struct or class in the object itself...but since you're using getters and setters the decision of how to represent it internally will be transparent to the users of the class anyways, so this decision will relate more to how complex the class is than anything.

2. One alternative to a setter is creating a new object, changing it, and returning it. This is both inefficient and inappropriate in most types, especially mutable types. However, it's an option that people sometimes forget, despite it's use in the string class of many languages.

Brian
+1  A: 

This technique is used in the Named parameter Idiom.

Fred Larson
+1  A: 

The typical purpose for this style is in use for object construction.

Person* pPerson = &(new Person())->setAge(34).setId(55).setName("Jack");

instead of

Person* pPerson = new Person( 34, 55, "Jack" );

Using the second more traditional style one might forget if the first value passed to the constructor was the age or the id? This may also lead to multiple constructors based on the validity of some properties.

Using the first style one might forget to set some of the object properties and and may lead bugs where objects are not 'fully' constructed. (A class property is added at a later point but not all the construction locations got updated to call the required setter.)

As code evolves I really like the fact that I can use the compiler to help me find all the places where an object is created when changing the signature of a constructor. So for that reason I prefer using regular C++ constructors over this style.

This pattern might work well in applications that maintain their datamodel over time according to rules similar to those used in many database applications:

  • You can add a field/attribute to a table/class that is NULL by default. (So upgrading existing data requires just a new NULL column in the database.)
  • Code that is not changes should still work the same with this NULL field added.
James Dean
+1 for compile-time safety.
Eclipse
Wow. That's an amazing adaptation to C++'s lack of named parameters (like Ada has had for 20 years).
T.E.D.
-> not . for pointers though :)
Greg Rogers
If you think that's crazy, take a look at boost::parameter http://www.boost.org/doc/libs/1_38_0/libs/parameter/doc/html/index.html
Eclipse
Sometimes you have to pass all the things to constructor to prevent memory leak if the one of the "Set" will throw.
Mykola Golubyev
+4  A: 

IMO setters are a code smell that usually indicate one of two things:

Making A Mountian Out Of A Molehill

If you have a class like this:

class Gizmo
{
public:
  void setA(int a) { a_ = a; }
  int getA() const { return a_; }

  void setB(const std::string & b) { v_ = b; }
  std::string getB() const { return b_; }
private:
  std::string b_;
  int a_;
};

... and the values really are just that simple, then why not just make the data members public?:

class Gizmo
{
public:
  std::string b_;
  int a_;
};

...Much simpler and, if the data is that simple you lose nothing.

Another possibility is that you could be

Making A Molehill Out Of A Mountian

Lots of times the data is not that simple: maybe you have to change multiple values, do some computation, notify some other object; who knows what. But if the data is non-trivial enough that you really do need setters & getters, then it is non-trivial enough to need error handling as well. So in those cases your getters & setters should be returning some kind of error code or doing something else to indicate something bad has happened.

If you are chaining calls together like this:

A.doA().doB().doC();

... and doA() fails, do you really want to be calling doB() and doC() anyway? I doubt it.

John Dibling
RE: "A.doA().doB().doC();" if doA fails, that's what exceptions are for.
Eclipse
+1, good point John. Also good point Josh.
j_random_hacker