Why Does "True or True and False" Appear to Be Simultaneously True and False

Why do both [] == true and ![] == true evaluate to false?

It's the way coercion works.

The first step of coercion is to convert any non primitive types to primitive types, then using a set of rules convert the left, right or both sides to the same type. You can find these rules here.

In your case [] == true, would pass through these 4 steps:

  1. [] == true
  2. [] == 1
  3. "" == 1
  4. 0 == 1

Whereas based on operator precedence the ! in ![] == true is executed first so the expression is converted to false == true which is obviously false.

You can try the live demo by Felix Kling to better understand how the sameness operator works.

In more words:

The value ![] is false, because [] is an Object (arrays are objects) and all objects, not including null, are truthy. So any array, even if it is empty will always be a truthy, and the opposite of a truthy is always false. The easiest way to check if a value is a truthy is by using !!.

console.log("![]: " + ![]);
console.log("!![]: " + !![]);

Ruby: why does `puts true and false` return true?

Because puts binds stronger than and: your code is equal to

(puts true) and false
true
#=> nil

You can check operators precedence in docs.

To get what you could use &&, which has higher precedence than and:

puts true && false
false
#=> nil

Combining boolean masks, why is in Python: [False, True] and [True, False] == [True, False]

This is the same reason why:

>>> (1,2) and (3,4)
(3, 4)

You need to understand that this is not doing element-wise comparison as opposed to np.logical_and.

The way and works is, if you have a and b, it checks whether a is False, if yes, return a else return b, does not matter what the value of b is.

In your case [False, True] is not False:

>>> bool([False, True])
True

Because it is a non-empty list, even [False, False] is True.
So in the case of [False, True] and [True, False], it checks to see whether [False, True] is False, which it is not, so it returns the second value. Same for the other case.

A python implementation of the and or logic would be:

def AND(first, second):
if bool(first) == True:
return second
else:
return first

def OR(first, second):
if bool(first) == True:
return first
else:
return second

Using | and & simultaneously in R (either values can be true, but neither can be false)

  • x & y - both must be true;
  • x | y - at least 1 is true (or both);
  • xor(x, y) - exactly one is true (not both);
  • !x & !y - neither is true. (Same as !(x | y).)

That should cover it pretty well.

If you data is binary (1s and 0s), 1 will be treated as TRUE, and 0 will be treated as FALSE, so you don't need to bother with a bunch of ==.

If you combine multiple logical operators, I'd strongly suggest using parentheses to make sure the order of operations/grouping is what you think it is.

m = expand.grid(x = c(0:1,NA), y = c(0:1,NA) )

## Truth Table
# x y x & y x | y xor(x, y) !x & !y
# 1 0 0 FALSE FALSE FALSE TRUE
# 2 1 0 FALSE TRUE TRUE FALSE
# 3 NA 0 FALSE NA NA NA
# 4 0 1 FALSE TRUE TRUE FALSE
# 5 1 1 TRUE TRUE FALSE FALSE
# 6 NA 1 NA TRUE NA FALSE
# 7 0 NA FALSE NA NA NA
# 8 1 NA NA TRUE NA FALSE
# 9 NA NA NA NA NA NA

In C++, why does true && true || false && false == true?

Caladain has exactly the right answer, but I wanted to respond to one of your comments on his answer:

If short-circuiting the || operator occurs and short-circuits the execution of the second && expression, that means the || operator was executed BEFORE the second && operator. This implies left-to-right execution for && and || (not && precedence).

I think part of the problem you're having is that precedence doesn't quite mean what you think it means. It is true that && has higher precedence than ||, and this exactly accounts for the behavior you're seeing. Consider the case with ordinary arithmetic operators: suppose we have a * b + c * (d + e). What precedence tells us is how to insert parentheses: first around *, then around +. This gives us (a * b) + (c * (d + e)); in your case, we have (1 && 1) || (infiniteLoop() && infiniteLoop()). Then, imagine the expressions becoming trees. To do this, transform each operator into a node with its two arguments as children:

Expression trees.

Evaluating this tree is where short-circuiting comes in. In the arithmetic tree, you can imagine a breadth-first bottom-up execution style: first evaluate DE = d + e, then AB = a * b and CDE = c * DE, and the final result is AB + CDE. But note that you could equally well have evaluated AB first, then DE, CDE, and the final result; you can't tell the difference. However, since || and && are short-circuiting, they have to use this leftmost-first evaluation. Thus, to evaluate the ||, we first evaluate 1 && 1. Since this is true, || short-circuits and ignores its right-hand branch—even though, if it had evaluated it, it would have had to evaluate the infiniteLoop() && infiniteLoop() first.

If it helps, you can think of each node in the tree as a function call, which produces the following representation plus(times(a,b), times(c,plus(d,e))) in the first case, and or(and(1,1), and(infiniteLoop(),infiniteLoop()) in the second case. Short-circuiting means that you have to fully evaluate each left-hand function argument to or or and; if it's true (for or) or false (for and), then ignore the right-hand argument.

Your comment presupposes that we evaluate everything with highest precedence first, then everything with next-highest precedence, and so on and so forth, which corresponds to a breadth-first bottom-up execution of the tree. Instead, what happens is that precedence tells us how to build the tree. The rules for execution of the tree are irrelevant in the simple arithmetic case; short-circuiting, however, is precisely an exact specification of how to evaluate the tree.


Edit 1: In one of your other comments, you said

Your arithmetic example necessitates the two multiplications to be evaluated before the final addition, is that not what defines precedence?

Yes, this is what defines precedence—except it's not quite true. It's certainly exactly true in C, but consider how you would evaluate the (non-C!) expression 0 * 5 ^ 7 in your head, where 5 ^ 7 = 57 and ^ has higher precedence than *. According to your breadth-first bottom-up rule, we need to evaluate 0 and 5 ^ 7 before we can find the result. But you wouldn't bother to evaluate 5 ^ 7; you'd just say "well, since 0 * x = 0 for all x, this must be 0", and skip the whole right-hand branch. In other words, I haven't evaluated both sides fully before evaluating the final multiplication; I've short-circuited. Similarly, since false && _ == false and true || _ == true for any _, we may not need to touch the right-hand side; this is what it means for an operator to be short-circuiting. C doesn't short-circuit multiplication (although a language could do this), but it does short-circuit && and ||.

Just as short-circuiting 0 * 5 ^ 7 doesn't change the usual PEMDAS precedence rules, short-circuiting the logical operators doesn't change the fact that && has higher precedence than ||. It's simply a shortcut. Since we have to choose some side of the operator to evaluate first, C promises to evaluate the left-hand side of the logical operators first; once it's done this, there's an obvious (and useful) way to avoid evaluating the right-hand side for certain values, and C promises to do this.

Your rule—evaluate the expression breadth-first bottom-up—is also well-defined, and a language could choose to do this. However, it has the disadvantage of not permitting short-circuiting, which is a useful behavior. But if every expression in your tree is well-defined (no loops) and pure (no modifying variables, printing, etc.), then you can't tell the difference. It's only in these strange cases, which the mathematical definitions of "and" and "or" don't cover, that short-circuiting is even visible.

Also, note that there's nothing fundamental about the fact that short-circuiting works by prioritizing the leftmost expression. One could define a language Ɔ, where ⅋⅋ represents and and \\ represents ||, but where 0 ⅋⅋ infiniteLoop() and 1 \\ infiniteLoop() would loop, and infiniteLoop() ⅋⅋ 0 and infiniteLoop() \\ 1 would be false and true, respectively. This just corresponds to choosing to evaluate the right-hand side first instead of the left-hand side, and then simplifying in the same way.

In a nutshell: what precedence tells us is how to build the parse tree. The only sensible orders for evaluating the parse tree are those that behave as if we evaluate it breadth-first bottom-up (as you want to do) on well-defined pure values. For undefined or impure values, some linear order must be chosen.1 Once a linear order is chosen, certain values for one side of an operator may uniquely determine the result of the whole expression (e.g., 0 * _ == _ * 0 == 0, false && _ == _ && false == false, or true || _ == _ || true == true). Because of this, you may be able to get away without completing the evaluation of whatever comes afterwards in the linear order; C promises to do this for the logical operators && and || by evaluating them in a left-to-right fashion, and not to do it for anything else. However, thanks to precedence, we do know that true || true && false is true and not false: because

  true || true && false
→ true || (true && false)
→ true || false
→ true

instead of

  true || true && false
↛ (true || true) && false
→ true && false
→ false

1: Actually, we could also theoretically evaluate both sides of an operator in parallel, but that's not important right now, and certainly wouldn't make sense for C. This gives rise to more flexible semantics, but one which has problems with side-effects (when do they happen?).

all() function gives TRUE but any() gives FALSE for same comparison

From the docs, any ignores zero-length objects:

...

zero or more logical vectors. Other objects of zero length are ignored, and the rest are coerced to logical ignoring any class.

How is this related to NULL == 1?

If we break this down, we see that NULL == 1 returns a logical(0) which is of length 0.

length(logical(0))
[1] 0

This is similar to:

any()
[1] FALSE

Now, why does all work?

The value returned is TRUE if all of the values in x are TRUE (including if there are no values), and FALSE if at least one of the values in x is FALSE. Otherwise the value is NA (which can only occur if na.rm = FALSE and ... contains no FALSE values and at least one NA value).

Note the including if there are no values part.

Compare this to the part in any's doc entry:

The value returned is TRUE if at least one of the values in x is TRUE, and FALSE if all of the values in x are FALSE (including if there are no values)

I think the main point is that since one is comparing NULL with something else, the returned logical vector is empty (i.e. length zero) which affects how the result is dealt with by any/all.



Related Topics



Leave a reply



Submit