Monday, September 10, 2007

C++: Fun With Comments

There's much fun to be had with C++ comments, and a lot of seriously usable tricks there as well. Of course, most of programmers already know all I could tell about the subject, but nonetheless, I think I'll take a shot at bringing all the techniques I think might be useful together, and I might be able to use a few possible tricks that a possible visitor would possibly leave on this post!
The first thing any programmer has to realize about comments is that (as their name suggests)
Comments are not the code that the compiler doesn't see, but the sentences that a human would read.
Write comments (and code in general) for another human (or you yourself) to read. This generally means you should generally avoid too clever constructs that have no other advantage. I say it again: Write code for other humans to read, not the compiler to compile.
You can use special comments and tools like doxygen to generate useful, beautiful, always-up-to-date and comprehensive documentation of your source codes automatically, with little extra work (e.g. with putting a line with three slashes ("///") at the beginning and describing the purpose of a function before its prototype.) These kinds of tools make you appreciate the value of comments!
My first advice is never use "//" or "/*" to comment out a piece of code. Those characters are reserved for "comments", i.e for writing descriptions of your code! Always put another character (or sequence of characters) after them, and use different characters to distinguish the different situations in which you've commented out the code. For example, use "//0" and "/*0" for code that you suspect is incorrect, use "//1" and "/*1" for test code, and so on and so forth. Keep in mind that these are only suggestions. Any system you opt to use, must be documented somewhere. Write 10 lines to describe the meaning and connotation of the 10 different types of comments you use. Don't take this lightly! As time goes by and you write more code, you'll accumulate these rules and split or merge them, but your commenting rules become more comprehensive, more concise and more useful.
Anyway, suppose you want to comment a multi-line piece of code. Always put the comment openning and closing on a line by themselves. No code on those lines! Also, use "//*/" for the closing marker (instead of just "*/".) This way, you can uncomment and recomment that part with only a single character; a '/' that you add to or remove from the beginning of the openning marker. Look at snippets 1 and 2.
There are times that you want to switch between commenting two parts of a single line. In these situations, you can put "/**" before the first part, put "/*/" between the two parts and "/**/" after the second part. Like snippets 3 and 4, you can then switch between the first part being commented out and the second one by adding a single '/' after the comment before the first part. (Also note the parsing/formatting bug of jEdit on line 18!)
You can also do it in the slightly prettier way that snippets 5 and 6 demonstrate (I really think so!) but only if you want to switch between two multi-line segments of code.
Commenting large blocks with "/*" and "*/" has a major problem. The commented blocks don't nest. For this reason, I suggest the cleaner method of using "#if 0", "#else" and "#endif" blocks (snippets 7 and 8, but they lack the coloring.) This way, not only you can nest commented out blocks inside of each other and enable/disable them individually just changing the '0' to '1' (provided the outer blocks are not disabled) but also you can comment the commented-outness(!) of these peices, and you can use preprocessor macros instead of just '0' to be able to switch these segments on and off from elsewhere. The only problem is that many editors and IDEs don't process preprocessor directives and they won't colorify the disabled parts as inactive.
In your "comment" comments, you can use well-recognized keywords like "NOTE", "WARNING", "TODO" and "FIXME" to make their meanings more apparent and to searching for them easier. Just remember to use them neatly and consistently.
If you have more ideas for using comments, I'd be happy to hear about them and to include them here. By the way, anybody has a clean and pretty way of switching (commenting/uncommenting) among three or more segments of code?
   1://{Snippet 1}
   2:/*0
   3:    for (unsigned i = 0; i < v.size(); ++i)
   4:        swap (v[i], v[v.size() - 1 - i]);
   5://*/
   6:
   7://{Snippet 2}
   8://*0
   9:    for (unsigned i = 0; i < v.size(); ++i)
  10:        swap (v[i], v[v.size() - 1 - i]);
  11://*/
  12:
  13://{Snippet 3}
  14:    for (unsigned i = 0; i < /**/ v.size() /*/ v.size() / 2 /**/; ++i)
  15:        swap (v[i], v[v.size() - 1 - i]);
  16:        
  17://{Snippet 4}
  18:    for (unsigned i = 0; i < /** v.size() /*/ v.size() / 2 /**/; ++i)
  19:        swap (v[i], v[v.size() - 1 - i]);
  20:        
  21://{Snippet 5}
  22:/*0
  23:    for (unsigned i = 0; i < v.size(); ++i)
  24:        swap (v[i], v[v.size() - 1 - i]);
  25:/*/
  26:    for (unsigned i = 0; i < v.size() / 2; ++i)
  27:        swap (v[i], v[v.size() - 1 - i]);
  28://*/
  29:        
  30://{Snippet 6}
  31://*0
  32:    for (unsigned i = 0; i < v.size(); ++i)
  33:        swap (v[i], v[v.size() - 1 - i]);
  34:/*/
  35:    for (unsigned i = 0; i < v.size() / 2; ++i)
  36:        swap (v[i], v[v.size() - 1 - i]);
  37://*/
  38:        
  39://{Snippet 7}
  40:#if 0
  41:    for (unsigned i = 0; i < v.size(); ++i)
  42:        swap (v[i], v[v.size() - 1 - i]);
  43:#else
  44:    for (unsigned i = 0; i < v.size() / 2; ++i)
  45:        swap (v[i], v[v.size() - 1 - i]);
  46:#endif
  47:        
  48://{Snippet 8}
  49:#if 1
  50:    for (unsigned i = 0; i < v.size(); ++i)
  51:        swap (v[i], v[v.size() - 1 - i]);
  52:#else
  53:    for (unsigned i = 0; i < v.size() / 2; ++i)
  54:        swap (v[i], v[v.size() - 1 - i]);
  55:#endif
UPDATE:I was wrong about the parsing/formatting bug in jEdit I mentioned above. That's a Doxygen comment and jEdit handles it correctly. Oops!

4 comments:

kentyman said...

I do a slightly different thing for switching between two blocks of code. Instead of this:

/**
function1();
/*/
function2();
/**/

I do this:

/*
function1();
/*/
function2();
//*/

It uses one less character, is easier for me to read, and is more consistent with the standard block comment we both use:

/*
function1();
function2();
//*/

yzt said...

Hi friend.
I think there has been some form of misunderstanding here. The syntax you suggest is the same as what I'd use and suggest. The first syntax you mention is what I'd recommend for switching between two blocks of code on the same line.
Your (and my) preferred syntax cannot be used for that purpose.

yzt said...

By the way, this is my old blog. My new blog is at http://yaserzt.com/blog/.

kentyman said...

Oh, I missed that. So you do this for single lines:

int i = /**function1()/*/function2()/**/;

And this for multiple lines:

/*
function1();
/*/
function2();
//*/

I've been using the latter for years, but the former is new to me. Good stuff!