What are logical operators? I sometimes find this question asked online and thought it would be good to explore in today’s episode. There are only three and you might think you already know how to understand them. But have you heard of short circuit evaluations? If you don’t fully understand how logical operations can sometimes exit early, then at best, you’re going to write some inefficient code. And most likely, you’re going to introduce some hard to find bugs.
The AND operator is used to build up a series of terms or conditions that all have to be true in order for the entire series to be true.
The OR operator is similar except that only a single term needs to be true in order for the entire series to be true.
The NOT operator just switches a single term to the opposite value.
The episode also describes short circuit behavior. This allows the AND operator to return early when it finds the first term that’s false. The OR operator can return early when it finds the first term that’s true.
Listen to the full episode or read the full transcript below.
Okay on to the question this week.
Some bugs happen all the time without doing anything special in a program. The QA team just writes down a series of repro steps that result in the buggy behavior. Repro is just short for reproduce. A repro step is something you need to do in order to hit the bug. This type of bug is said to be 100% reproducible.
Other bugs start out being documented like the simple case. Yet when a developer tries following the steps, the program works just fine. The bug ticket can sometimes go back and forth as the details are discovered. Once the exact steps are refined, the bug is again at 100% repro rate.
Some bugs can never be fully defined like this and might be due to some timing issue that’s outside of direct control of the QA team or the developers. These bugs might have a repro rate of 10%, 20%, or whatever seems reasonable. Most of the time, the percentage is just a guess.
If you don’t understand how logical operators work, then you’re more likely to introduce bugs that fall into the second category that take a bit more effort to pin down or sometimes even into the third category that can never be fully reproducible.
So now that you know how important this topic is, what are the three logical operators? The first is “and”. The second is “or”. And the third is “not”. It can sometimes be a little hard to say them without getting them confused with the normal word and that comes before the last item in a list.
These operators work by themselves or in combination to specify a true or false condition. You normally find them inside if conditions, while loops, or in return statements. Let’s look at what each one does by itself first.
The and operator is used to build up a series of terms or conditions that all have to be true in order for the entire series to be true. You need at least two conditions to test for this operator to make any sense. Why at least two? Well imagine if I told you “In order to win the game, you need to score at least 50 and…” Now if I just ended my statement like that, it doesn’t make any sense. I need to finish maybe like this, “In order to win the game, you need to score at least 50 and your character must survive.” Now it makes sense.
We could add a third term as well. Let’s say this is a rogue game and you also want to arrive at the end with a full backpack. If anything is missing or stolen, then you lose no matter what your score is. This new expression would then read like this, “In order to win the game, you must have a score of at least 50 and you must survive and you must have a full backpack.”
We have three terms and they must all be true in order to win. But a single processor can only look at one of the terms at a time. So if the processor first tests the score and finds it to be less than 50, what does that mean? It means you lost the game and it doesn’t matter if your character survived or not or if your backpack was full or not. Because it doesn’t matter, then the compiler will write code to end the evaluation early. This is called a short circuit evaluation and can save your program from running code that won’t matter.
I personally prefer to call this a shortcut evaluation because in electronics, a short circuit is normally a bad thing. That’s when you start seeing smoke and hearing sizzling sounds coming from your project. Not good at all. But it’s good in programming. Let me expand on that. It’s good in programming if you as a developer are expecting this possibility.
What you don’t want to happen is for there to be code in those other two terms that you need to run. Because you should not and cannot rely on them to be run. As long as you’re aware of this behavior, you’ll be fine. Run the code that needs to be run first, save the result of each term in it’s own variable, and then test the results. Don’t try to do both at the same time or you may find that certain outcomes cause some of your code to be skipped as well. That could be a hard bug to find.
With the and operator, all the terms must be true in order for the entire expression to be true. And the moment any of the terms is found to be false, then that’ll cause the rest of the terms to be skipped and the whole expression will be false.
The next logical operator is or. This works very similar to and except that in this case, the entire expression will be true as long as any of the terms are true. Just like the and operator, you need at least two terms for the or operator to make any sense.
If you have ten terms and just one of them is true, then the entire expression is true. That doesn’t make the other nine terms true. They’re still false. But that single true term out of ten is enough to make the entire expression true. What if two of the terms are true? Doesn’t matter, It only takes one. Three? Doesn’t matter. It only takes one.
This means that the or operator can also be short circuited. But it will short circuit the moment it finds a term that’s true. The and operator short circuits when it finds the first term that’s false.
And the third logical operator is not. The not operator only needs a single term. All it does is change it to the opposite value. If a term is true, then not true becomes false. And if a term is false, then not false becomes true.
Why would we need a logical operator that just changes things like this? Imagine that our rogue game expressed your character’s liveliness as “did your character die” instead? And what if it referred to the backpack contents not as if the backpack was full but instead as “is anything missing?”
With these changes, we need to also change the test of the winning expression so it reads like this, “You win the game as long as your score is at least 50 and you’re not dead and your backpack is not missing anything.” See how the not operator slips in there to reverse the meanings of the second and third terms?
That’s it for logical operators. Different languages might have different syntaxes or different ways of writing the operators, but the concept of the three logical operators should exist in any language.