Hello, and welcome to C++ Weekly.
I'm your host Jason Turner.
I'm available for code reviews, contracting,
and on-site training.
In this episode, I am going to attempt
to show you a subtlety of short circuiting
with our logical operations that just it caught me recently.
And I was kind of surprised, and it took me
a little while to debug this.
And it probably shouldn't have.
But I just thought I would share it here on C++ Weekly for all
of you to look at this and think about it yourselves and see
if you've ever had the similar kind of issue come up.
Now, for those who aren't aware, short circuiting in C++ in any
language that has short circuiting means that it's only
going to execute as much of the operation as it needs
to, and this is often a good thing.
So if you say, if--
so if we do something like this-- now,
this isn't going to compile, but I'm just using the compiler
explorers and editor at the moment--
if operation 1 and operation 2.
Now, if operation 1 fails, then it's
not going to execute operation 2, because it already knows
that this condition has failed.
Now, I got started in Basic, and Basic it
didn't have short circuiting, but I
have been programming in languages
that do have short circuiting since about 1995 approximately.
So this is definitely something that I am used to now,
and this comes up in the real world.
We might do something like, if argc is greater than 1,
and argv of 1, something, something, in here.
Because we're going to double check
to make sure that we actually have more than one argument,
and then we know that we can access the second argument
in the list.
So I was recently programming, working on my arm emulator
that I have mentioned a couple times now on here,
and I had code that looked kind of like this.
Now, there is a subtle logic bug in this code,
and I will leave it up here for a few seconds
to give you a moment to look at it,
and perhaps, you'll see the issue.
I did not immediately see it.
I made a change similar to this, and then I had, down here,
some like check.
If I did work, then do some other operation.
And I think this is specifically like I was going through my GUI
event and loop, and if something changed,
then I knew that I needed to redraw
a certain part of the GUI.
Basically like this, and we have it
in a way that compiles here, although it's not
terribly meaningful to look at.
It took me probably 30 minutes to debug
this, before I realized that what was happening
is I never executed my try doing work more than once.
I would stay here in this busy loop,
constantly checking some condition
to see if it was true, while I was looping around.
And then I would get here, and I would
say, did work equals did work, or try doing work.
And if did work was now true, because at one point
we had come through and actually did do some work,
then it would never execute this try doing work ever again.
So it'd only execute it at most once,
no matter how long check condition was actually
true for.
So this was bad, and I ended up changing it to something like--
so this way, I could have gotten the actual logic
that I wanted from it.
So I'm actually doing work, as long as the condition is true,
and then only updating that did work flag when
that's the correct thing to do.
This though has so many little subtleties in it.
I could have done this instead.
So in this case, I will execute the first condition,
no matter what.
Did I do some work when I executed try doing work?
If I did, in fact, then did work will be true.
Otherwise, if did work was already true,
then the condition remains true--
seems like a pretty good idea.
I ultimately did not go with this one
though, because this seemed basically too
fragile for refactoring here.
If someone in the future were to look at this line of code
and get this logic backward again,
then we would end up in the same situation again.
Where we're only executing work once
per check condition flag being set for whatever thing
was going on here.
So this is just an interesting little thing here,
and maybe just an FYI.
If you are relying in some non-obvious way
for logical short circuiting to do some particular thing
that you want it to do, then I would
suggest a comment or a subtle refactoring to the something
so that it is clear to the future readers of your code
what the actual goal was.
Now, to be clear, the kind of check that we do
like all the time--
again, this isn't going to compile.
I'm not going to bother making it compile.
But if you're doing something like this,
where you are relying on short circuiting
to first check if the condition is true
and then do something with it, that's perfectly fine.
Do that throughout your code.
That's good, but I think this is one of the maybe just handful
of times in my entire career that a short circuiting
with an or operation just threw me off,
and it took me a little while to debug it.
So just a silly mistake on my part,
but I thought I would share it here on the show,
and I hope you liked this episode.