Thursday, September 4, 2008

Convenient setters in C++?

Libzypp's RepoInfo class was originaly written with property setters returning a RepoInfo & reference to the modified object. This pattern is common in higher OO languages like Java and is convenient as it saves typing when setting serveral properties at once (i'm not sure how it is performance-wise).


RepoInfo repo;

// you write
repo
.setAlias("foo")
.setName("Foo Project Repository")
.setEnabled(true).setAutorefresh(false);

// instead of
repo.setAlias("foo");
repo.setName("Foo Project Repository");
repo.setEnabled(true);
repo.setAutorefresh(false);


Unless the class is part of a class hierarchy, everything's OK. But after splitting RepoInfo to RepoInfoBase and a derived RepoInfo the dark side of C++ has shown up.


RepoInfo repo;
repo
.setAlias("foo") // RepoInfoBase setter
.setEnabled(true) // RepoInfoBase setter
.setPriority(50); // RepoInfo setter - this won't compile becase setEnabled() returned
// a RepoInfoBase &, and C++ does not bother with figuring out that the
// object is also a RepoInfo.


In order to make this work in this setup, you have to redefine each setter from the base class in the derived class and make it return the reference to the derived class:


class RepoInfoBase
{
RepoInfoBase & setAlias( ... ) { _pimpl->alias = ...; return *this; }
}

class RepoInfo : public RepoInfoBase
{
RepoInfo & setAlias( ... )
{ RepoInfoBase::setAlias(...); return *this; }
}


but by doing this the RepoInfo class looses some of the advantages of being derived from RepoInfoBase.

So, is it best to stick with setters returning void, or is there a better way to do this?

1 comment:

wekempf said...

The "Curiously recurring template pattern" (http://en.wikipedia.org/wiki/Curiously_Recurring_Template_Pattern) might help here.