Journal Articles

CVu Journal Vol 17, #2 - Apr 2005 + Programming Topics
Browse in : All > Journals > CVu > 172 (12)
All > Topics > Programming (877)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: Forgetting the ABC

Author: Administrator

Date: 03 April 2005 13:16:11 +01:00 or Sun, 03 April 2005 13:16:11 +01:00

Summary: 

Body: 

I recently bought and read "C++ Coding Standards" by Sutter and Alexandrescu [Sutter-], without expecting many surprises. Like most seasoned C++ professionals, I've read Sutter's "Exceptional" and Meyers' "Effective" series, as well as numerous articles, which coupled with long experience of using the language has made me reasonably confident that I don't commit too many sins.

Indeed, I wasn't surprised by anything I read, although I might not have agreed completely with everything either. Those are minor quibbles, though, and not really worth mentioning. What did surprise me was an omission. Of course, any collection of best practice guidelines has to tread a line between the terse and verbose, and on the whole I think the authors have made a good job. I just wish they hadn't missed what I have always thought of as the ABC principle - Always Be Conventional.

To be fair, it is covered, albeit in a couple of specific instances. Items 26 (Preserve natural semantics for overloaded operators), 27 and 28 (Prefer the canonical form[s of +, +=,++, and the minus equivalents]) and 55 (Prefer the canonical form of assignment) are all expressions of ABC.

However, while it is important to follow the principle when dealing with operators, I was surprised that there was no generalisation of it, since it is a common problem anywhere an established convention exists.

Here is a simple example I once found in production code:

template<typename A_, typename B_,
         typename C_>
struct trio {
  A_ first;
  B_ second;
  C_ extra;
  ...
};

This is clearly inspired by std::pair and while I have omitted all but the essential members, it should illustrate the point. The struct is well named, implying where the idea came from, and it can be used as a pair would, with a first and second member. And then there's an extra member... I can see the logic there, but it's such a silly thing to do. Why isn't the C_ member called third?

Okay, so that's just annoying but not dangerous per se. Here is another example, again found in production code, which really boggled me:

template<typename A_>
class matrix {
  vector<A_> data_;
  long width_, height_;
public:
  // STL style functions mirroring the
  // std::vector interface

  ...
  void resize(long w, long h) {
    data_.resize(w*h);
    width_ = w;
    height_ = h;
  }
  ...
};

This implementation of resize does not fulfil my expectations. While the behaviour of the function does what it says on the tin, it doesn't do enough. By designing the class interface to resemble that of a standard container, the programmer has implicitly promised to follow the convention already established by the STL. If I have data in the matrix and resize it, I would expect that the elements in the cells that remain in the matrix are unchanged, which is the canonical behaviour. This is not the case here, since there is no shuffling around of existing data if I change the width.

As a user of the matrix class, I will carry with me an assumption of what the function resize will do in a container, based on my knowledge of an established convention. Any piece of code that draws on such a convention should adhere to it completely, or clearly document where it does not. In this example, the offending function should really be called resize_dirty, or be rewritten to conform to the expected behaviour.

These are just two examples - I have seen many, many more. Neither is it only applicable to operators and STL look-alikes. If I were to create a new label control using [MFC] to show the text in rainbow colours, for instance, I would make sure that the function to provide it with a text to display would be called SetWindowText and have the same form as the canonical one. Sadly, judging from what I've seen over the years, the common practice would be to call it SetText or SetRainbowLabelText.

ABC is basic wisdom and common sense, just like KISS, and it bears repeating. While Sutter and Alexandrescu devote four out of one hundred and one items to special cases, they fail to point out the underlying general principle. I do not know whether this was through oversight or because they considered it too obvious, but personally, I feel it is an important principle that is neglected too often.

It's just a matter of following conventions where they exist, fulfilling expectations and avoiding putting in surprises for other developers (or oneself, in six months time). Sometimes, if all your friends are jumping off a cliff, you really should do so too.

References

[Sutter-] Herb Sutter and Andrei Alexandrescu, C++ Coding Standards, Addison-Wesley, 2004

[MFC] Microsoft Foundation Classes, the class framework created by Microsoft to create GUI applications for Windows, in which window classes have a SetWindowText member.

Notes: 

More fields may be available via dynamicdata ..