I have always been lousy at card games. I console myself that it doesn't mean I'm stupid; rather, my short-term memory is not so hot. I just can't hold many things in my head at the same time. I guess I am not alone. One of the first lessons new programmers learn is, "Abstraction is your friend." It is a good lesson, and a comforting one, because it hints that other programmers need help managing complexity as well. Maybe they can't hold much in their heads at the same time either.
Later on, these new programmers may learn another lesson, "Abstraction isn't the answer to everything." This lesson is not so comforting. Abstraction has hidden costs, the best known being decreased performance. Templates are often hailed as a cost-free abstraction mechanism, but apparently they have yet to work their magic on the STL. To see what I mean, check out Dan Saks' column this month (p. 65). Dan has been conducting a few experiments with STL performance on various compilers and libraries. Although his findings are preliminary, they suggest that you take a good hard look before using STL containers in performance-critical projects. Maybe someday they'll be as fast as anything you could craft by hand; we haven't gotten there yet.
There are a couple of ways to respond to this inverse relationship between abstraction and performance. One way, the way of the idealist, is to simply deny it. You can say to yourself, "If only those compiler and library vendors would get it right," or tell yourself we just need to discover a few new magic techniques. The history of computing does not support this view. The other way to respond is to acknowledge the troubling fact and deal with it as best we can. We don't go running back to assembly language, for God's sake. We should hang onto as much abstraction we can afford.
Here is a simple question to help gauge affordability: how many things will I have to remember to use this abstraction safely and effectively? The more things you have to hold in your head, the less useful the abstraction.
An example of an easily affordable abstraction in C++ is the iterator. You can use an iterator much like a regular pointer, to access the elements of a standard container. But there is a hidden gotcha. If you're iterating over a vector, and you stop to add or remove elements, your iterator may become invalid unusable, kaput. This is virtually guaranteed if the vector has to reallocate storage. There is nothing in the iterator's interface that warns you of this possibility. You just have to know. That makes one thing to remember, which is not too bad considering how much you gain.
Now consider the article, "A Concise Method For Evaluating Derivatives," by Ronald Huss, Mark Pumar, and Robert Rudin (p. 18). They have come up with a way to automatically compute the derivatives of mathematical expressions. No more differentiating the formula symbolically by hand (or if you're lucky, with a tool like Mathematica), and then plugging the result into your code. You just write the expression to be differentiated and go. Cool, but now there are at least two things to remember: first, there is a lot of computation going on behind the scenes, so performance is going to suffer; second, you can't just use any expression you have to stick with the ones supported by the library. Still, I think the benefits of this abstraction outweigh the drawbacks. If I didn't, we wouldn't be printing it in CUJ.
Over the course of a year, a lot of manuscripts pass over my desk presenting some clever new abstractions to make notation more intuitive, say, or to reduce the amount of typing required. When evaluating such manuscripts, I ask myself the question I posed above. Three or more things to remember and I start to get nervous. I also ask whether the abstraction does more to clarify, or obscure, the intent of the programmer. For instance, I'm generally leery of schemes to cram as many operations as possible into a single line of code. The new notation is rarely as intuitive as the author believes.
I am not suggesting you use a rigid set of criteria for evaluating abstractions. I sure don't. I rely on a variety of things questions like the above, advice from my Senior Editor, and my nose. I am not sure, but I suspect there are no perfect abstractions. It's a messy, big lasagna of a world out there. The best we can do is keep the layers as separate as we can, and not fret about the places where they mix.
Marc Briand
Editor-in-Chief