Correction: The Right Way To Manage State in C++

03 Mar 2014 . category: . Comments

In a previous post, I described a simple “Television” class in C++. The class itself is syntactially correct–what I wrote was good C++ code. The problem, though, was that the code had a pretty serious bug in it. In this post, we’ll talk about what the bug was, and how to go about addressing it.

The Television class had a header file like so…

…and a pressPowerButton() implementation like so.

While this served the purpose of my post, a friend smarter than me pointed out a little problem. By flipping tvIsOn before testing it, and then calling turnOn() or turnOff(), I am making the assumption that turnOn() and turnOff() will never, ever fail.

Why? Let’s consider the case where the TV is off. If the TV is off, and I press the power button, and for whatever reason the TV doesn’t turn on, I’m hosed. Because I already flipped the state variable to be “true”, the TV object thinks it’s in the on state, when it really isn’t.

Ick. That’s a problem, huh? One of the most common pitfalls in programming is assuming nothing will ever go wrong. Murphy’s law would disagree with that assumption. So how do we address this flaw in our code? One way would be to let turnOn() and turnOff() (henceforth referred to as our state change functions) decide what the new state is.

In order for this to work, these functions now need to return a boolean. While we’re at it, we might as well have pressPowerButton() return a boolean that tells the user what the new state is. This way, the user can check to see if the tv is behaving the way they expected. Our patched header file looks like this.

Now, let’s look at our implementation.

That’s much better. Now, I’m testing to see what the state is before I try changing it. Based on what the state is, I attempt to move to a new state. If the state is “on”, I try to go to the “off” state, and vice versa. The state change functions now will return what the new state is. For example, if turnOff() manages to successfully complete, it will return “false”, which corresponds to the “off” state. Should it fail, it will return “true”, meaning that the tv is still in the on state.

Additionally, the user gets back communication on what happened when they called pressPowerButton(). If she were expecting the TV to turn on and it stays off, she now knows she’s got a problem, and she knows it’s within the Television object, not her code that manipulates it.

Whew! Let this be an important lesson–in programming, being an optimist without a good reason can bite you in the butt. While the code I started with should always work, there are far too many circumstances where it won’t. To build programs that are robust and avoid inexplicable crashes, we need to do better.

All the code featured in this post is available in a GitHub Gist, here. Code embedding comes courtesy of Blair Vanderhoof’s awesome gist-embed.


Me

Vishal Kotcherlakota is a reformed sysadmin, who writes code and will talk incessantly about DevOps to anyone who will listen. All views expressed here are his and not those of his employers.