Overloading or obfuscation? - Embedded.com

Overloading or obfuscation?

Operator overloading is a powerful feature of the C++ language. Used with care, it can yield readable, maintainable and efficient code. However, it is just as easy to write “clever” code which is apparently elegant, but, in reality, is hard to understand and, hence, unmaintainable. This article gives examples of good and bad practice and investigates how and where an embedded developer might make good use of operator overloading.

Readable code
What is the key objective when you write some code? The obvious answer is that you want to impart some specific functionality to the device that you are programming. That would be fine, if just designing and writing code was all that a software engineer was required to do. There are several programming languages that would enable code to be written very rapidly. An example, that I have an affection for, is Forth. With this language you can crank code very quickly indeed and it can be quite efficient, particularly on memory footprint. The problem comes when you try to read the code later. I have heard people describe Forth as a “write only programming language” and I can see their point.

This is the crux of the issue. Developers only spend a small proportion of their time writing new code. They expend a good deal more effort maintaining and enhancing existing software. So, the real answer to my initial question should be that you are communicating the design of your algorithms and procedures to the poor guy who will maintain the code at some future point (which may, of course, be you!).

So, writing clear, well commented code is vital. This rather puts the nail in the coffin for Forth, but opens up some possibilities in languages like C and, more so, C++. The key to writing clear, easy to understand code is to aim for its functionality to be obvious by making everything as intuitive as possible. Identifiers should have meaningful names – that is a good start. C++ classes should behave in obvious ways. Things like enums should be exploited widely. Also, operators should be overloaded to make the code more readable.

Operator overloading for clarity
Operator overloading is very neat. When you define a class, you specify some data (member variables) and operations that might be performed on/using that data (member functions). You can also include some special member functions that implement the standard C++ language operators (like +, -, *, >> , etc.) for your class. For example, imagine you have two objects, instantiated from the same class, called alpha and beta and you wish to add beta to alpha (we do not need to know exactly what “add” means in this context). This might be done using a member function like this:

   alpha.add(beta);

But this is not very intuitive. An alternative is to overload the += operator so that you can write:

   alpha += beta;

This is much clearer. You could also overload + (and = ) so that the operation could be coded this way:

   alpha = alpha + beta;

This is ideal for all frustrated Basic, Pascal and FORTRAN programmers.

Overloading operators
The syntax for operator overloading is reasonably straightforward. The code to implement the operator functionality is simply a class member function with a special name. This name is constructed from the keyword operator and the operator symbol or name that is to be overloaded. Here is a fairly self-explanatory example:

   class stuff
   {
     unsigned data;
     …
   public:
     stuff(unsigned);
     …
     void operator+=(unsigned);
     …
   };

   void stuff::operator+=(unsigned val)
   {
     data += val;
   }

Operator overloading for obfuscation
Although operatoroverloading can be used to clarify code, it can also be used to make itharder to understand. For example, when I was first learning C++, I readin a book that overloading + could be used to write code like this:

   alpha + beta;

Iwas very confused, as this should just be an expression, the result ofwhich is discarded. Then I realized that it was really the += operator that should have been overloaded, as this was the functionality imparted to the + operator.

Generally,overloading operators should be performed so that the resulting use isconsistent (or identical) to the original meaning of the operator forstandard data types. This is the case in the examples above. However,there are exceptions. I am not sure how I feel about the standardoverloading of << and >> for stream I/O objects, like this:

   cin >> i;
   cout << i * 2;

This accepts an integer and outputs the result of multiplying it by 2. Normally << and >> are used to denote bit shifting.

Operator overloading for embedded code
Embeddedsoftware developers are always a little conservative and only adopt adifferent approach if there are clearly demonstrable benefits – verymuch a case of “If it ain’t broke, don’t fix it.” This explains therelatively slow take-up of the C++ language for embedded applications.

Oneof the challenging areas of embedded development is working close tothe hardware. It is not uncommon for peripheral devices to need somevery arcane programming, which leads to errors by other members of thedevelopment team, who are not knowledgeable about the hardware inquestion. It is likely to be hard for a reader of the code to understandhow such interfacing software works.

Using C++ objects to hidesuch “difficult” code is a common approach. It is then a challenge tomake those objects as easy and intuitive to use as possible. Imagine aspecialized device that has some kind of 32-bit register and the codeneeds to set bit 2. It might need some code like this:

   specialdevice.setbit(0x0004);

But maybe it would be easier if the designer of the object overloaded the |= operator to achieve the same result, thus:

   specialdevice |= 0x0004;

I, for one, think that this code is more intuitive to write and clearer to understand.

Conclusion
Operatoroverloading is a powerful feature of the C++ language. If used well, itcan make code easier both to develop initially and understand later.Used badly, the resulting code can be very hard to interpret. Forembedded developers, operator overloading enables specialist developers,who fully understand the underlying hardware, to present theapplication programmers with a more intuitive interface, which resultsin fewer errors and more readily maintainable code.

Colin Walls has over thirty years experience in the electronics industry, largelydedicated to embedded software. A frequent presenter at conferences andseminars and author of numerous technical articles and two books onembedded software, Colin is an embedded software technologist withMentor Embedded (the Mentor Graphics Embedded Software Division), and isbased in the UK. You can visit his regular blog or email at .

4 thoughts on “Overloading or obfuscation?

  1. Really? You had to take a cheap shot at Forth? It is entirely possible to write “clear, well commented code” in Forth and obfuscated, poorly commented code in C / C++. It depends on the programmer, not the language.

    Log in to Reply
  2. I think Mr. Walls was pointing out that in embedded programming clarity of the code both for the purpose of maintenance and logic flow is imperative and Forth being based on Reverse Polish notation and having no type checking is unsuitable. Forth is, as he

    Log in to Reply
  3. I take your point Losgann, my comment about Forth did appear harsh, but that was the result of the necessity for brevity. As Twburger points out, the readability of code is really the responsibility of the programmer, but it is nice when the language encou

    Log in to Reply
  4. I think “specialdevice.bit[3] = 1;” would be more friendly than “specialdevice |= 0x0004;”; but “specialdevice.function_active = true;” would be better (where “function_active” describes the role of the bit in a way that “true/false” would fit as values).

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.