Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Understanding "logical OR" and "logical AND" in programming languages
Many programming languages either have keywords like or
and and
used for logic, or equivalent operators such as ||
or &&
- which are referred to as "logical or" and "logical and" respectively in the language documentation. However, these tools don't seem to work in a natural or expected way for many beginners. Which is to say: "translating" an English sentence into code, using or
or ||
to represent the English word "or", etc., commonly causes errors or gives the wrong result.
Why is this? What are the semantics of these operators, and how is that different from a natural-language understanding? And why are they called "logical"? (Are there other kinds?)
3 answers
They aren't actually that different from natural language. But more verbose. Given some generic pseudo code looking like one of the C family languages:
if( !egg.boiled || !egg.peeled )
{
do_not_eat(egg);
}
Then this is to be translated as:
"If the egg is not boiled or the egg is not peeled, don't eat it."
In everyday English we would probably rather say:
"If the egg isn't boiled or peeled don't eat it."
Confusion arrises because we don't repeat the noun over and over in everyday English. We wouldn't say "If the egg isn't boiled or the egg isn't peeled or the egg isn't smashed", we would say "if the egg isn't boiled, peeled or smashed".
And so beginners may think they can write code like if (a == 1 || 2 || 3)
because that's how you'd say it "in your head" when writing the code.
But programming languages usually demand that we are more verbose and refer to the object in every sub expression. In this example the equality ==
operator is the one doing the comparison and that one is defined by the language syntax to take two operands. As are the ||
logical OR operators.
We just have to fall in line and follow the language syntax, which isn't so much there for the convenience of the human brain as for the compiler implementers having a fighting chance to understand the programmer's intention. Consider for example if (a == 1 || 2 || b == 3)
, we can't just guess which variable the 2
is to be compared with.
Similarly, most languages do not support "interval syntax" as seen in math: 0 < i < n
. Here too we have to use operands with two operators for each <
and in order to glue them together, an additional AND: if (0<i && i<n)
. Or perhaps more readable for a programmer, keep the changing variable to the left side consistently: if (i>0 && i<n)
.
Notably, if we use common sense and turn the wording around in our head: "If the egg is not boiled or the egg is not peeled, don't eat it."
We might simply just say:
"If the egg is not boiled and peeled, don't eat it"
Note the change from or
to and
here. The new wording has the same meaning, but only if egg
refers to not (boiled and peeled)
. From this we can conclude that
(the egg is not boiled) or (the egg is not peeled)
is equivalent to
the egg is not (boiled and peeled)
.
If it is either not boiled nor peeled, then it can't very well be boiled and peeled.
By just using common sense we have actually applied what Boolean algebra refers to as
De Morgan's laws - more info here: Understanding "de Morgan's laws".
As for why they are called logical, that goes back to digital electronics, which uses terms that go back to the mathematician George Boole and the term logic ultimately originates from classic Greek, math and philosophy. Before there were computers, there were logic gates, which are electronic components in the form of integrated circuits based on transistors.
For example an AND gate is an integrated circuit where you could enter two voltages on two pins and if both voltages were high, you would get a high voltage out. Otherwise a low voltage. You'd describe the behavior of the gate with something known as a truth table, here illustrating one for an AND gate:
input1 input2 output
0 0 0
0 1 0
1 0 0
1 1 1
0 means low voltage and 1 means high voltage. Or if you will: 0 is false and 1 is true. So this directly corresponds to and
/&&
operators in programming. In fact the schematic IEC symbol for an AND gate is a &
.
Some programming languages do in fact have other forms of AND/OR than the logical ones. Low-level languages like C have another category of operators that work on a bit level rather than Boolean level. They are called bit-wise operators and low-level languages typically have a bunch of them: bit-wise AND &
, bit-wise OR |
, bit-wise XOR ^
and so on. Also there are bit shift operators, moving all binary digits n steps to the left or right.
I won't go into how these work here as there's plenty of learning material out there. Also these come with various language-specific quirks to them.
0 comment threads
One thing I'd like to add to Lundin and r.zwitserloot answers, which is something that I think is rather important:
The "or" in programming is inclusive. The "or" in most languages (all those I know of: "or", "ou", "ó", "order"...) is exclusive.
If we look at the truth tables of the AND, OR, and XOR we have:
A B AND OR XOR
-----------------
0 0 0 0 0
1 0 0 1 1
0 1 0 1 1
1 1 1 1 0
^ ^
| |
| +--- language OR
|
+--- language AND
As we can see, in a programming language "if A or B ..." means that A can be true, B can be true, or A and B can be true. In our languages, if A and B are both true, we often don't use the work "or".
Do you want the blue or the red pill?
On top of that, in most programming languages, you do not have a logical XOR operator. You often have a bitwise XOR, though. Usually using ^
character, at least in C and derivatives.
One way I've seen people deal with the inclusive "or" in English is by using the "and/or" double conjunction: A and/or B ...
1 comment thread
The explanation is that human languages are fundamentally confusing on this, but, because humans tend to be somewhat blind to complexities in systems that they've literally been the only thing they've known since before they have memory (you tend to learn to speak well before persists-into-adulthood memories). So they think and+or is less complex than it is.
Some trivial jokes that highlight this:
Jane asks Joe to go to the store to buy a loaf of bread. Oh, and if they have eggs, buy 10.
Joe returns with 10 loaves of bread. Jane, exasperated, asks Joe what the heck he thinks he's doing. Joe answer: "... they had eggs".
Alex asks Sasha if she wants her cake with whipped cream or without whipped cream.
Sasha says: "Yes".
More generally, the principle at work is that you need parentheses in order to determine order of precedence when you infix your ands and ors. Here's a simple truth table:
A or B and C
can mean different things depending on how you resolve it (how you determine the precedence there). It can mean:
- A or (B and C)
- (A or B) and C
For example:
If it rains or the sprinkler system is on, and the swimming pool isn't covered, the water level inside it will be raised. (this is (A OR B) and C
where A is rain, B is sprinkler, C is pool cover).
if it rains or I'm standing over the sprinkler and the sprinkler is on, I will get wet. (this is A or (B and C)
where A is rain, B is standing over the sprinkler, C is the sprinkler is on.
So why isn't this confusing to you?
Because of context. You are visualizing the situation. Linguistically there is no difference here. It is not possible to tell. If I actually meant this hard to imagine bizarre scenario, where you get wet only if:
- It is raining or you are standing over the sprinkler.
- AND, regardless, the sprinkler must be on.
(i.e. (A or B) and C
), then I can say the exact same sentence and it can be interpreted that way equally validly.
The reason you don't interpret it that was is because you're not an idiot, and you have an imagination: You are seeing the sprinkler, standing outside, in the rain, and so on. You know which of the two linguistically equally likely explanations is the obvious intent of the speaker. But this requires vast amounts of context, and, is ambiguous - context cannot always make clear which one is clearly intended; ambiguity is generally hated in programming languages for fairly obvious reasons.
So, in programming languages, parentheses are used, and those new to coding find it difficult. Because it is difficult and that 'applying the context to figure out what was intended' is something they've been doing since they were 3 years old, so it's difficult to realize you're even doing that.
There are exotic solutions of course. such as using postfix syntax. This:
- A B C and or
- A B or C and
(That's RPN - Reverse Polish Notation. A
pushes A on the stack, B
pushes B on the stack, or
pops 2 values off the stack and applies the OR operation on them, then pushes that on the stack. The result of the calculation is that one thing is on the stack and that is your answer).
isn't ambiguous and yet does not require parentheses. But, while I'm not a psychologist, I find it natural that it is easier to understand operations if the operands are as close to the operator as possible. This isn't always the case with RPN. That's presumably why most languages don't go for this (stuff like PostScript and Forth - stack based languages, really are written like this, though!)
1 comment thread