21

I'm writing a pretty large library, and I find myself writing almost identical accessors all the time. I already have several dozen accessors such as the one below.

Question: How can I declare/implement accessors to save typing all this repetitive code? (No #defines please; I'm looking for C++ constructs.)

Update: Yes, I do need accessor functions, because I need to take pointers to these accessors for something called Property Descriptors, which enable huge savings in my GUI code (non-library).

.h file

private:
    bool _visible;
public:
    bool GetVisible() const { return _visible; }
    void SetVisible (bool value);

// Repeat for Get/SetFlashing, Get/SetColor, Get/SetLineWidth, etc.

.cpp file

void Element::SetVisible (bool value)
{
    _visible = value;
    this->InvalidateSelf(); // Call method in base class
    // ...
    // A bit more code here, identical in 90% of my setters.
    // ...
}

// Repeat for Get/SetFlashing, Get/SetColor, Get/SetLineWidth, etc.
adigostin
  • 633
  • 7
  • 20
  • Some IDEs have a feature to generate this code for you. – Neil Kirk Nov 29 '15 at 13:40
  • Your SetVisible functions are different. Which do you want to generate? – Neil Kirk Nov 29 '15 at 13:41
  • Ed Heal, the if statement makes sense in my software (still under development and InvalidateSelf very costly), but I agree is doesn't make sense here in my question. I'll remove it. – adigostin Nov 29 '15 at 13:43
  • CPP macros are the traditional solution. – bmargulies Nov 29 '15 at 13:44
  • 1
    No C++ constructs. Use an X MACRO or generate the code. – Karoly Horvath Nov 29 '15 at 13:47
  • 2
    I think we need more of an example here: Are you trying to avoid writing a `SetVisible` for a dozen classes, or are you trying to avoind writing a `SetVisible`, `SetShaded`, `SetBold`, `SetItalic` for a single class? – Mats Petersson Nov 29 '15 at 13:47
  • I would further argue that typing in the class declaration shouldn't be considered a bad thing in and of itself. – Mats Petersson Nov 29 '15 at 13:48
  • 17
    Easy: avoid accessors. Program your classes to do something, rather than have something. – n. m. could be an AI Nov 29 '15 at 13:50
  • I ask myself if you really need to write getter and setter for EVERY member of your class. giving access to only few needed members seems legit, if any one of the members is accessed it mught as well be public.. – David Haim Nov 29 '15 at 13:51
  • Mats Petersson, I made an edit to clarify this (it's indeed SetBold, SetShaded and so on.) – adigostin Nov 29 '15 at 13:54
  • 1
    I agree too many getters/setters suggests bad design, but sometimes it's easier said than done. For example, you can set a breakpoint in a getter to see when it is read. Can't do that on a public field. – Neil Kirk Nov 29 '15 at 14:01
  • 3
    Wow, changing the question and thereby completely breaking the existing answers. Great, thanks for that. – Lightness Races in Orbit Nov 29 '15 at 14:02
  • 1
    @adigostin If you want a comprehensive answer you need to provide details. The generalities you've given favor Lightness's answer, though whether that may translate to actual code is another problem, therefore needful of another question. – edmz Nov 29 '15 at 15:01
  • 3
    Lightness, reading back on the initial version of my question, I do agree that the interpretation that comes first to mind may be "how to avoid accessors?", which would favor your answer. I should have made it clear from the very beginning that I need to take pointers to these accessor functions; sorry about that. – adigostin Nov 29 '15 at 20:42
  • 1
    After more than five years on Stack Overflow you should know by now that ,to comment-reply to people, you should use "@person" syntax. Otherwise they are not generally notified about your response; I stumbled upon yours to me only by chance. Thanks. – Lightness Races in Orbit Nov 30 '15 at 00:39
  • So, what are these "property descriptors"? Do they have to be pointers to methods on the type, or are they a sensible `std::function< X(T const&) >` and `std::function< void(T&, X const&) >`? If not the second, why aren't they something sensible? – Yakk - Adam Nevraumont Nov 30 '15 at 00:46
  • @Yakk, I use property descriptors for saving to / loading from XML my entire hierarchy of objects (among other purposes). They're not something "sensible" because I also need to compile my library for ARM with IAR Embedded Workbench, which lacks a lot of "sensible" C++ features. – adigostin Nov 30 '15 at 07:55

5 Answers5

33

I find myself writing almost identical accessors all the time. I already have several dozen accessors such as the one below.

This is a sure design smell that you are writing accessors "for the sake of it". Do you really need them all? Do you really need a low-level public "get" and "set" operation for each one? It's unlikely.

After all, if all you're doing is writing a getter and a setter for each private data member, and each one has the same logic, you may as well have just made the data members public.

Rather your class should have meaningful and semantic operations that, in the course of their duties, may or may not make use of private data members. You will find that each of these meaningful operations is quite different from the rest, and so your problem with repetitive code is vanquished.

As n.m. said:

Easy: avoid accessors. Program your classes to do something, rather than have something.

Even for those operations which have nothing more to them, like controlling visibility, you should have a bool isVisible() const, and a void show(), and a void hide(). You'll find that when you start coding like this it will promote a move away from boilerplate "for the sake of it" getters & setters.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    Totally agree. You can have a OOP C++ but, please, do not make it look like Java. No need to duplicate such abomination. Don't use OOP for the sake of it. – edmz Nov 29 '15 at 13:56
  • 2
    @black: Using OOP for the sake of it is kind of okay, but getting OOP _wrong_ for the sake of it is not. :) And, yes, I know this is how they teach it at schools (sadly). – Lightness Races in Orbit Nov 29 '15 at 13:58
  • Lightness - wrong answer (I didn't ask about its smell). See my Update. – adigostin Nov 29 '15 at 14:01
  • 1
    @adigostin: Okay then you know best. – Lightness Races in Orbit Nov 29 '15 at 14:02
  • 2
    A public setter/getter pair for a private data member has one big advantage over a public data member: You can easily temporarily add a log line or a breakpoint and can debug every access without having to modify all code that access that property. Often one does not know, how much a certain member may get accessed 10 years later. – Kaiserludi Nov 30 '15 at 11:47
  • @Kaiserludi: Ah yes, that old myth. [Read and enjoy](http://stackoverflow.com/a/12108025/560648). – Lightness Races in Orbit Nov 30 '15 at 12:49
  • @Lightness: I don't think that you got my point. I am talking about temporary changes for debugging purposes, not about permanent breaking changes to the functionality. – Kaiserludi Nov 30 '15 at 13:20
  • @Kaiserludi: For that case, you do not need to "modify" or "add" anything; this is what debuggers and watches are for. – Lightness Races in Orbit Nov 30 '15 at 16:59
27

Whilst I think Lightness Races in Orbit makes a very good point, there is also a few ways that can be used to implement "repeating code", which can be applied, assuming we do indeed have a class that have "many things that are similar that need to be controlled individually, so kind of continuing on this, say we have a couple of methods like this:

void Element::Show()
{
   visible = true;
   Invalidate();
   // More code goes here. 
}

void Element::Hide()
{
   visible = false;
   Invalidate();
   // More code goes here. 
}

Now, to my view, this breaks the DRY (Do not Repeat Yourself) principle, so we should probably do something like this:

void Element::UpdateProperty(bool &property, bool newValue)
{
   property = value;
   Invalidate();
   // More code goes here. 
}

Now, we can implement Show and Hide, Flash, Unflash, Shaded etc by doing this, avoiding repetition inside each function.

void Element::Show()
{
    UpdateProperty(visible, true);
}

If the type isn't always bool, e.g. there is a position, we can do:

template<typename T>void Element::UpdateProperty(T &property, T newValue)
{
   property = value;
   Invalidate();
   // More code goes here. 
}

and the MoveTo becomes:

void Element::MoveTo(Point p)
{
    UpdateProperty(position, p);
}

Edit based on previously undisclosed information added to question:

Obviously the above technique can equally be applied to any form of function that does this sort of work:

void Element::SetVisible(bool value)
{
   UpdateProperty(visible, value);
}

will work just as well as for Show described above. It doesn't mean you can get away from declaring the functions, but it reduces the need for code inside the function.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Mats, I added your templated UpdateProperty as a protected function in a base class and now most of my setters can be one-line. I actually tested that, so I'll accept your answer. – adigostin Nov 29 '15 at 20:46
  • 2
    @adigostin Protected methods are often a sign of a design smell. Not always, but most of the time it means that you are using inheritance for implementation sharing. I think this and the need for `setters` is a clear sign that there is a problem on the design level, e.g. wrong level of abstraction. – Jens Nov 30 '15 at 07:58
7

I agree with Lightness. You should design your classes for the task at hand, and if you need so many getters and setters, you may be doing something wrong.

That said, most good IDEs allow you to generate simple getters and setters, and some might even allow you to customize them. You might save the repetitive code as a template and select the code fragment whenever needed.

You may also use a customizable editor like emacs and Vim (with Ultisnips) and create some custom helping functions to make your job easy. The task is ripe for automation.

enitihas
  • 835
  • 1
  • 9
  • 17
  • 1
    You may also use Sublime text, and add custom autocompletes, so you need not write them completely over and over! – Sahil Arora Nov 30 '15 at 14:33
0

The only time you should ever write a get/set set of functions in any language is if it does something other than just read or write to a simple variable; don't bother wrapping up access to data if all you're doing is make it harder for people to read. If that's what you're doing, stop doing anything.

If you ever do want a set of get/set functions, don't call them get and set -- use assignment and type casting (and do it cleverly). That way you can make your code more readable instead of less.

This is very inelegant:

class get_set {
    int value;
public:
    int get() { return value; }
    void set(int v) { value = v; }
};

This is a bit better

class get_set_2 {
     value_type value;
     bool needs_updating;
 public:
    operator value_type const & () {
        if (needs_updating) update(); // details to be found elsewhere
        return value;
    }

    get_set_2& operator = (value_type t) {
        update(t); // details to be found elsewhere
        return *this;
    }
};

If you're not doing the second pattern, don't do anything.

Clearer
  • 2,166
  • 23
  • 38
  • 1
    If you don't like this answer, please let me know why. – Clearer Nov 30 '15 at 08:58
  • I did not vote for your answer, but I guess that your statement that getters/setters should be avoided unless they do anything "interesting" is too strong for many readers, especially in the way that you phrase this. Adding getters and setters without "need" allows to add interesting code later to the classes, without breaking compatibility with the code having been written until then. Overloaded assignment operators leads to potential problems being missed during code review (as it is not clear that something interesting happens at that point), which is why not everyone likes them. – DCTLib Nov 30 '15 at 12:49
  • The reason for overloading assignment is to allow code compatibility without using a get/set set of functions. If you always just assume that it's overloaded for custom types, it shouldn't lead to any problems during code review (hasn't for me so far). – Clearer Jan 14 '16 at 19:36
0

I'm a tad late again, but I wanted to answer because I don't totally agree with some other here, and think there's additional points to lay out.

It's difficult to say for sure if your access methods are code smells without seeing a larger codebase, or have more information about intent. Everyone here is right about one thing: access method are generally to be avoided unless they do some 'significant work', or they expose data for the purpose of generic-ism (particularly in libraries).

So, we can go ahead and call methods like the idiomatic data() from STL containers, 'trivial access method'.

Why not use trivial access methods?

First, as others have noted, this can lead to an over-exposure of implementation details. At it's best such exposure makes for tedious code, and at it's worse it can lead to obfuscation of ownership semantics, resource leaks, or fatal exceptions. Exposure is fundamentally opposite of object orientation, because each object ought to manage its own data, and operations.

Secondly, code tends to become long, hard to test, and hard to maintain, as you have noted.

When to use trivial access methods?

Usually when their intent is specific, and non-trivial. For example, the STL containers data() function exists to intentionally expose implementation details for the purposes of genericism for the standard library.

Procedural style-structs

Breaking away from directly object-oriented styles, as implementation sometimes does; you may want to consider a simple struct (or class if you prefer) which acts as a data carrier; that is, they have all, or mostly, public properties. I would advise using a struct only for simple holders. This is opposed to a class ought to be used to establish some invariant in the constructor. In addition to private methods, static methods are a good way to illustrate invariants in a class. For example, a validation method. The invariant establishment on public data is also very good for immutable data.

An example:

// just holds some fields
struct simple_point {
    int x, y;
};

// holds from fields, but asserts invariant that coordinates
// must be in [0, 10].
class small_point {
  public:
    int x, y;

    small_point() noexcept : x{}, y{} {}
    small_point(int u, int v) 
    {
        if (!small_point::valid(u) || !small_point::valid(u)) {
           throw std::invalid_argument("small_point: Invalid coordinate.");
        }

        x = u;
        y = v;
    }

    static valid(int v) noexcept { return 0 <= v && v <= 10; }
};
Hunter Kohler
  • 1,885
  • 1
  • 18
  • 23