Ahhh... today's task was going to be a cakewalk. I had some minor changes to make in a module I'd written not too long ago. I took a swig of the caffeinated drink stuff that some people in the lunchroom call coffee, sat back in my chair, and settled in to look at my code.
What in heck is this? I wondered:
void f() { TextHandler t; t.sendText("Hello, world", true); // ... }
I couldn't remember what the Boolean parameter meant. I had to look up the class definition to remind myself:
class TextHandler { public: void sendText( const std::string & msg, bool sendNewLine ); //... };
Ah, of course, I mused, the warm glow of familiarity returning (helped along by another sip of coffee), the function appends a carriage return/line feed if the parameter is true. How could I have forgotten?
Snap! That would be the Guru snapping her huge tome closed. I managed not to spill any coffee in my surprise. After recovering my composure, I turned to greet her and was again taken aback. Her book was a tiny paperback that couldn't have contained more than a hundred pages. I was mystified how she had managed to extract such a resounding thwack from such a little book.
"My child, if you can forget so easily what the parameter means, how do you expect other programmers to understand, when they are looking at your writings for the first time?"
"Uh, well," I hemmed and hawed, "Don't most of our source editors show the function's parameters when you hold the mouse over the function?"
"Some, my child, but not all or even most. I have oft preached that the primary purpose of source code is communication communication of intent from one programmer to another. The book in my hands is an old, well-respected tome on the art of communication. In here, it is written, 'use definite, specific, concrete language' [1]. In your parable, bool is none of these. It conveys nothing useful to the reader."
"Uh, no, but it's not that hard to remember once you know, is it?" The Guru fixed her steely blue eyes on me. I was getting decidedly hot under her gaze.
"How long ago did you write this code?" the Guru's voice was mild too mild for my liking.
"So, um, how should I fix it?" I neatly sidestepped her question.
"Can you think of no other way to express your intention?" Yep, sidestepped my way out of the frying pan into the fire.
"I could eliminate the second parameter and force the user to send the newline," I said as I wrote on the whiteboard:
{ t.sendText("Hello, world\n"); }
"The thing is, though, the code that uses the TextHandler usually prints a variable just before the line terminator, not a hard-coded string," I continued writing, "so I'd have to do this:"
{ t.sendText( variable1 ); t.sendText( ":" ); t.sendText( variable2 ); t.sendText( "\n" ); }
"I am not convinced that your writings would suffer greatly from such a change, my child. However, for the sake of further, deeper enlightenment, let us assume that the distinction is necessary. How else could you achieve this?"
"Well, I could provide two separate functions, I suppose:"
void sendText( const std::string & ); void sendTextWithNewLine( const std::string & );
"Hmmmm... yes, that could work for your particular case," the Guru frowned slightly as she considered it. "Any other possibilities?"
She wasn't letting me off easily today. I thought furiously for a moment, then... gave up. I shrugged my shoulders at her.
The Guru picked up the whiteboard marker. "There is another aspect to this quest you are undertaking, my child. Consider this parable:"
void displayText( const std::string &, bool applyItalics, bool applyBold ); void f() { displayText( "This is bold but not italic", true, false ); }
"The intent is to have the text appear in bold, but the poor scribe that wrote the parable has been confounded by the order of the parameters. The text will appear in italics. The compiler will not flag such a failing, for the compiler sees nothing out of the ordinary.
"Now consider what would happen if Bob got at the code and re-ordered the parameters, a technique known as 'Permute And Baffle'[2]:"
void displayText( const std::string &, bool applyBold, bool applyItalics );
"The disciple who created the false writings, the problematic displayText, has failed to require definite, specific, concrete parameters.
"Neither of your two solutions would work. The displayText function requires additional parameters to indicate the disposition of the text. This smites down your first solution. Your second solution would work, but it would be quite brittle. In the event additional formatting styles such as color, font type, and so on are added, the number of functions required will grow exponentially. Yet there is another solution which you have not... ahem... enumerated..." She paused.
"Enumerations?" I asked.
"Very good, my child. Yes, enumerations would serve your purpose quite well here. Behold:"
class TextHandler { public: enum NewLineDisposition { sendNewLine, noNewLine }; void sendText( const std::string &, NewLineDisposition ); }; void f() { TextHandler t; t.sendText( "Hello, ", TextHandler::noNewLine ); t.sendText( "world", TextHandler::sendNewLine ); }
"These writings are good. The code is now self-documenting you will note there is not a comment in sight, yet the intent and end result are perfectly clear. Disciples meditating upon the function f() do not need to interrupt their thoughts to look up what the parameters to sendText mean.
"The enumeration has the added blessing that it is quite easily extensible. Should you ever need to send a carriage return before the string, for example, then it is a simple matter to add an enumeration such as prependNewLine, and none of your existing code will break.
"Do not lose heart and discard your first solutions, my child. In other quests, they may be the worthy champions that vanquish the demons of the solution domain." She turned, reopened her book, and gracefully glided away, around the corner.
Notes
[1] William Strunk Jr. and E.B. White. The Elements of Style (MacMillan Publishing Co. Ltd, 1979).
[2] From Roedy Green's "How To Write Unmaintainable Code," <http://mindprod.com/unmaindesign.html>. (Primarily aimed at Java programmers, it still has lots of relevance for C++ programmers.)
Jim Hyslop is a senior software designer at Leitch Technology International Inc. He can be reached at [email protected].
Herb Sutter (<www.gotw.ca>) is convener of the ISO C++ standards committee, author of the acclaimed books Exceptional C++ and More Exceptional C++, and one of the instructors of The C++ Seminar (<www.gotw.ca/cpp_seminar>). In addition to his independent writing and consulting, he is also C++ community liaison for Microsoft.