The safe bool idiom in C++

I’m in the process of writing a series of articles on C++11, and a passing explanation of this idiom grew to become a whole article. There’s no original content here, but I learned something in writing it and I hope it might be useful to someone out there.

It’s idiomatic C++ to evaluate a variable in boolean context, even when it’s not a boolean variable, to detect whether that variable is “not a thing”. For example, with a pointer variable it checks whether the pointer is null or not:

if (my_pointer) {
   // my_pointer is not null
}

Exactly what this boolean conversion means varies by type, but experience shows that one’s intuitive sense of how this should work is pretty consistent and this can make code more expressive. Some would say this is bad practice, but for now I’ll assume that it’s desirable.

If you’re writing a user-defined class, you want to follow this kind of pattern if possible. If 0 is false, then surely the (0, 0, 0) point in a 3D space is false? Of course, C++ lets you make your user-defined type act pretty much however you want it to, so of course you can define an implicit conversion to bool:

struct TestResult {
   //...
 
   operator bool() const {
      return m_passed;
   }
};

The problem with this is that it’s not just a conversion to bool. It’s a conversion to a type that is part of a system of numeric types, and the types allow conversions between them that allow you do do silly things. For example, you can assign it to an integer:

TestResult test_result;
int i = test_result; // Should really be a compile error

More insidiously, things like the left-shift operator suddenly work on your objects in ways that you might not expect:

test_result << i;

As is the way with all C++ design issues, you can get around this by careful application of edge cases of language tools that were meant for something else. You can expose a conversion to any type you like. Void pointers are a reasonable thing to try, because there’s not a lot you can do with a void pointer:

struct TestResult {
   operator void *() {
      return m_passed ? this : 0;
   }
};

There’s no implicit conversion of void pointers in C++, so this seems reasonably safe. However, one thing you can do with a void pointer is call delete, and there’s no way to prevent that from compiling:

TestResult tr;
delete tr; // Gets converted to pointer, attempts to delete a stack variable!

You could try returning a pointer other than this, which could eat least mean that the code would crash horribly the moment delete was called:

struct TestResult {
   operator void *() {
      return m_passed ? (void *)1 : (void *)0;
   }
};

But this is horrible. Besides, there’s no guarantee that you won’t segfault just by referencing pointers to non-allocated portions of memory (i.e. segfault even in the good case where you’re just converting the result straight to boolean).

A common trick in C++ (which dates from an earlier related trick in C) is to give code an incomplete type to work with. If you have a class declaration in scope, but no definition, then you can handle pointers to the incomplete class but there are limits to what you can do. In particular, you can’t dereference or delete the pointer. So you can safely pass such a pointer back to the caller and allow them to compare it with NULL without worrying that they can delete it.

How can you get a pointer to a type that you can be sure won’t be defined? You define one for yourself. A nested class will do nicely:

struct TestResult {
  //...
 
  class never_defined;
 
  operator const never_defined*() {
    return m_passed ? reinterpret_cast<const never_defined *>(this) : 0;
  }
};

Unfortunately, while pointers to incomplete types can’t be dereferenced, you can still compare them:

TestResult x, y;
 
// later ..
 
if (x > y) // Really shouldn't compile
{
 // ...
}

Can we prevent this? Just one more dip into the junk draw of C++ will sort us out. One of the more overlooked features of C++: the pointer-to-member (in this case, a pointer to member function).

A pointer to member isn’t like a regular pointer. A regular pointer points to data of a particular type in the memory space. A pointer to member operates in the world of classes, not objects. The pointer to member identifies a member of a particular type on a particular class; if you have a int Foo::*, it can point to any integer member of the Foo class. When you set the value of your pointer-to-member, it points to that same member on every instance of Foo (or, equivalently, on no particular Foo instance at all).

Pointers to member can’t be compared to each other, so we can combine our conversion-to-pointer trick with a pointer-to-member and have (at last) a safe boolean conversion:

struct TestResult {
  //...
 
  typedef void (TestResult::*bool_type)() const;
  void do_nothing() const;
 
  operator bool_type() const {
    return m_passed ? &TestResult::do_nothing : 0;
  }
};

If you’re not used to unpacking these definitions, the line:

typedef void (TestResult::*bool_type)() const;

deserves some explanation. This is just like any other typedef, except that since it’s a function typedef the name of the type defined (bool_type) goes in the middle and not on the right hand side. The TestResult::* bit identifies that we’re defining a type that points to a member of TestResult, rather than a regular pointer. The remaining stuff just tells us that we’re talking about a const function that takes no arguments and returns void.

For an example of this being done in the wild, you can see the safe_bool class within Boost::Spirit.

Learning programming with stories

Over a year ago I came across Python Pals, a project to write stories that motivate young people to learn programming. I always intended to write about the project but forgot to do so.

The concept for the stories is inspired by the Bytes Brothers stories of old, and follows a similar format: in each story, the pair of young protagonists come across a problem (such as calculating the exact age difference between their parents) that gives rise to a simple solution that they work together to implement. The story contains code snippets that the reader can use to follow along for themselves.

I love the concept, and the stories are certainly a refreshing change from the status quo in teaching programming. Using female protagonists is a nice modernisation, though I found the trendy inclusion of a Raspberry Pi irritating: you don’t need a Raspberry Pi to learn to write command-line programs in Python. In fact, the Pi can only make the task harder and implies that special equipment is needed (laptops that are capable of running Python are still massively more ubiquitous than Raspberry Pi’s, despite the latter’s low price and status as a media darling).

My instinct is to worry that this story-based approach is solving the wrong problem: my own experience was that it was very easy to get started with simple command-line programs and much harder to get as far as making things that felt like “real” programs. The idea that computers could be made to do things came easily to me, but I felt that writing a tool or game that someone else would want to use was well out of my reach. I’d have been better cutting my teeth on something that made the installer and GUI easy, such as the Android platform (or even not-quite-programming environments like writing AVS presets).

But I don’t have a lot of experience teaching young people to program, and my experience was a long time ago and may be atypical, so I’m happy to be proven wrong here. I don’t think we need to be teaching all children to program, but we should be providing resources for all those who are interested. A diverse range of solutions has to be a good approach.

Unused employee creativity

I’ve been reading about the Toyota Production System (TPS) recently. As everyone knows, one of its key principles is eliminating waste in the production system. Waste is defined much more broadly than you might first assume, but it makes sense: anything that doesn’t add value to the customer is waste.

As I looked down the list of eight sources of waste, one of them caught my attention:

  1. Overproduction
  2. Waiting (time on hand)
  3. Unnecessary transport of goods
  4. Over-processing or incorrect processing
  5. Excess inventory
  6. Unnecessary movement of staff
  7. Defects
  8. Unused employee creativity

I wasn’t expecting “unused employee creativity” to be considered, let alone to be given equal footing to the other types. There’s a tendency to think of Toyota and TPS as extremely conservative and valuing of strict procedures, and not at all open to creativity.

I think what brings these two concepts together is another Toyota principle:

“Make decisions slowly, considering all the possibilities. Act quickly.”

The decision process is conservative by virtue of taking its time and requiring evidence before something is changed, not by virtue of considering a small number of possibilities.

For a long time I’ve felt that there is a false dichotomy between the popular visions of small dynamic start-ups and conservative larger companies. Perhaps this example provides a useful model how companies can be exceptions to this rule.