Unreliable Intuitions

Qt is a really wonderful and nice toolbox, and I thoroughly enjoy working with it, so it’s unfortunate that I’m using it for my example of one of the many things wrong with C++. In my opinion C++ is a kludge for bolting the Object Oriented paradigm onto a language barely more sophisticated than assembly. This unholy marriage has resulted in a language that is rife with special-case exceptions and horrifically complicated syntax. Just take a look at the STL and you can actually feel the hemorrhage of pre-mature optimization.

Anyway, Pointers are long known to be the most problematic concept for students of C/C++. Truly grokking pointers took me about 2 weeks initially, and I still get to enjoy learning another nuance about every other month. The ability to control the memory of your machine is a power not to be accepted lightly. We had an opportunity to leave pointers behind with Fortran and Lisp, but K&R apparently enjoyed living at the machine level. To this day we still get to hold pointers responsible for much of program ailments. (buffer overflow, memory leaks, null dereference, etc…)

One of the other real sticky issues that novices have to deal with is the difference between the stack and the heap. This is usually introduced alongside the introduction of pointers, because the two concepts are rather intricately related. But all this just makes the conceptual cliff a bit steeper. Eventually, the junior programmer develops a nice intuition about allocation and optimization, and when to use stack vs when to use head and handle the memory yourself. Then, the awesome power granted to us via pointers rears its ugly head.

Straight from the Qt Documentation on QString

Note for C Programmers

Due to C++’s type system and the fact that QString is implicitly shared, QStrings may be treated like ints or other basic types. For example:

     QString Widget::boolToString(bool b)
         QString result;
         if (b)
             result = "True";
             result = "False";
         return result;

The result variable, is a normal variable allocated on the stack. When return is called, and because we’re returning by value, the copy constructor is called and a copy of the string is returned. No actual copying takes place thanks to the implicit sharing.

Well, isn’t this nice? Because of pointers we are permitted a really handy optimization. But, most of the time strings aren’t long enough to justify the sacreligious violation of hard-won intuitions. The real problem here is that nothing apparent in the syntax of this little snippet that lets the programmer know what’s really going on. It looks like everything is being copied from the stack to the return value. So we are obligated to read the documentation (which you should do for any toolkit, as they all do things like this) or possibly shoot ourselves in the foot.

Now this particular optimization is fairly well known, and used in many container classes. I’m not faulting Qt here, I put the blame squarely on the design of C++. This is a premature optimization, that messes with things behind-the-scenes, and it violates our intuitions. I would be willing to accept this type of behavior if there were some syntactical clue, but there isn’t. Programmers, esp. those writing toolkits, are really smart people, and I recognize their superior skills in crafting the incantations that permit the journeyman to have optimized code nearly by accident. But it’s still magic, and the language’s we use should be more explicit.

Note: This particular design has never caused me any troubles. I’m writing this from a linguistic design point of view. I don’t think it’s safe to give ourselves this type of power, because, ultimately, I know that this behind-the-scenes style black-magic has been abused and subsequently gotten many of us in serious trouble. Violating user expectations is always a sin.