November 22, 2013
I’ll bet that most developers have experienced the application of this bit of wisdom at one time or another:
There are only two hard things in Computer Science: cache invalidation and naming things.
– Phil Karlton
Indeed Michael Feathers blogged recently about the difficulty of naming a method that might do nothing. Since most code is read much more often than it is written, choosing the correct name for a method or a variable is extremely important. Good names can make complex code understandable, while bad names can leave even the simplest code nearly impenetrable.
Don’t even name it##
If a good name is valuable, then no name is priceless. Often I find myself writing code which uses object temporarily, but gives it a name that out lives its usefulness. Not only does this make code less readable, but it is down right dangerous.
Consider the following example, taken from Anthony Williams excellent book Concurrency in Action:
The C++11 threading library requires that either
detach() is called on a
std::thread object. This code will not call either though, if
do_something_that_might_throw() indeed does throw an exception. Williams comes to the rescue with an RAII class to save the day.
So the code in
might_throw() above can now be written like this:
In this trivial example, it is easy to see that
t.join() should not be called now. But in a more complex method that you might find in real code, it may not be clear to someone later that the call to join the thread is not necessary (and, in fact, dangerous).
Find the temporary##
The fundamental problem here is that we have given a name (
t) to an object that is really a temporary. By using the
guard class to handle the lifetime of the thread, we have eliminated the need for the method which creates the
std::thread to ever use it. So rather then refactoring the code to change the name of
t to something like
t_do_not_use, we can avoid giving the thread a name altogether. I would really like to do something like this:
In C++98, this won’t work, because the
guard constructor is passed a reference to a temporary object. The C++11 standard introduced move semantics, which allow a temporary object to be moved instead of copied, so I can write the code I want to write (with a few changes to the
guard class). After Williams mentions that a
std::thread can be moved, he updates the RAII code like this:
So now the calling code is safer. There is no name for the
std::thread object, so it cannot be used incorrectly later in the method.
So as a developer, I need to consider not only what I should name a variable, but even if I should name the variable. With move semantics in C++, it is now easier to be explicit about the context in which a given variable is used, and possible to avoid naming it unnecessarily.