How could I negate the value of the entire statement with !
as per additional experementing advice? It’s not like with the previous example where there is a boolean set in variable. So how can I use the bang operator on the two comparisons to negate them?
we could simple use the bang operator at both conditions:
console.log( !false && !false );
or we can use the order of operations to our advantage:
console.log( !(false && false) );
parentheses are evaluated first, so the order is:
parentheses -> and operator -> bang operator
It is not a bang
operator in JavaScript, but in Ruby. In JS it is the NOT operator.
Any truthy expression in any form will be cast to a boolean and negated, so will yield, false
. The opposite will happen when we negate a falsy expression and will yield, true
.
I have a query about the different positioning options of the not operator !
in an if()
conditional statement, and the requirement (or not) of brackets, depending on the desired outcome. For example:
// both conditions T: prints pass
let x = 'blue';
let y = 5;
if (x === 'blue' && y <= 5) {
console.log('pass');
} else {
console.log('fail');
}
If we wanted to negate the whole conditional statement, could the above code be modified using either of the following?
// both conditions T, but ! reverses to F: prints fail
if (!(x === 'blue' && y <= 5))
or
// both conditions T, but ! reverses to F: prints fail
if (!x === 'blue' && y <= 5)
i.e. I get the same result with or without the brackets, so am I right to assume that, here, precedence rules mean that the brackets are optional? However, would use of the brackets be preferrable due to readability?
If instead of negating the whole conditional statement, we wanted to negate both conditions separately before applying the logical operator, could the code in our original example be modified using either of the following?
Note: I’ve also made the following additional two changes to the example:
(i) mathematical operator <=
(less than or equal to) changed to >
(greater than); and
(ii) logical operator &&
(and) changed to ||
(or).
// 1st condition F, 2nd condition T: prints pass
if (!(x === 'blue') || !(y > 5))
or
// 1st condition F, 2nd condition T: prints pass
if (x === !'blue' || y > !5)
Even though my own ‘trial and error’ testing has given me the outcomes above, I want to check that all of these syntax alternatives are both valid and good practice, as I’m aware that my limited testing may not paint the whole picture.
a = true, b = true
In any configuration with AND, NOT will render as false
.
! a && ! b // <- false
! a && b // <- false
a && ! b // <- false
! (a && b) // <- false
Different configurations with OR, not will render as false
when applied to both operands, and true
when applied to only one operand.
! a || ! b // <- false
! (a || b) // <- false
! a || b // <- true
a || ! b // <- true
Your last example is a bit off the beaten path. When we apply NOT directly to a non-boolean it first casts the value to a boolean, then negates it.
! 'blue'
'blue'
is cast to true
since a sting of any length but zero is truthy. NOT toggles it to false
However the logic is little fuzzy since the expression,
x === ! 'blue'
is akin to writing,
x === ! x
which is an oxymoron.
! 5
becomes false
as well, since any number but 0 is truthy, and toggling that gives false
.
Any number greater than zero is greater than false
.
5 > false // <- true
-5 > false // <- false
This brings us to strict versus loose comparison.
0 === false // <- false
0 == false // <- true
Notice how the double =
coerces the 0
to a boolean.
At any length, that last example is one to avoid owing to its mutation of objects before the comparison. That kind of logic could lead to some serious problems if it is not very thoroughly tesed and backed by sound reasoning.
I’m still uncertain, as the original exercise in the lesson doesn’t use variables with boolean values (as you have with a = true
and b = true
). Instead it uses one variable with a string value, and another with a number value (as in my example x = 'blue'
and y = 5
. Am I right in understanding that the boolean values arise when these non-boolean values are ‘tested’ with comparison operators in the conditional statement? i.e.
… with both conditions, here, rendering the boolean true
?
If this is the case, then could you confirm that what I have deduced as follows is correct for my example if( && )
statement (with mathematical comparisons)?
When the variables:
x = 'blue';
and
y = 5;
A)
if (!x === 'blue' && y <= 5)
and
if (!(x === 'blue' && y <= 5))
Both result in ‘false’ for the same reason, whether brackets or not are used.
First, the two comparisons render (true && true)
= true
Then the !
negates this to give a final result of false
.
B)
if (!x === 'blue' && y > 5)
and
if (!(x === 'blue' && y > 5))
Note <=
has changed to >
First, both render (true && false)
= false
for the same reason, whether brackets or not are used.
Then the !
negates this to give a final result of true
.
C)
if (!(x === 'blue') && !(y > 5))
Here brackets must be used if our intention is to negate each comparison separately before applying the &&
operator.
First, the two comparisons render (true && false)
Then the two !
negate both booleans separately to give (false && true)
, which gives a final result of false
.
D)
if (!(x === 'red') && !(y > 5))
Note blue
has changed to red
Again, brackets must be used if our intention is to negate each comparison separately before applying the &&
operator.
First, the two comparisons render (false && false)
Then the two !
negate both booleans separately to give (true && true)
, which gives a final result of true
.
Finally…
I totally get that this is…
… and applies twisted logic that I wasn’t intending. So, let’s just forget about that one as something accidently stumbled-across while ‘playing around’
But they are both truthy, so not much difference.
Think of outcome. Non-boolean values still have a potential to be truthy or falsy. Only a truthy value can make it into the first branch of an if statement. Their outcome evaluates to true
but the value does not change. Control flow passes to the first branch and that code is executed.
When expression A is truthy and espression B is truthy, the outcome of ANDing in a conditional branch is to hand control flow to the first branch. There is no conversion of either operand. Only their truthiness is evaluated.
Draw out three truth tables…
AND T F
T t f
F f f
OR T F
T t t
F t f
NOT
T f
F t
TL; DR. Have to come back to this. Please bear with me.
No problem… no urgency, just appreciate your attempt to ‘untangle’ my understanding.
I think I can see now that each of the ‘comparisons’ (e.g. y > 5
) in my conditional statement example, even though based on non-boolean values, will evaluate to either true or false. Then, depending on which logical operators (&&
, ||
or !
) are also applied, an overall evaluation of truthiness will be arrived at for the conditional statement as a whole, of either:
true - executing the code block in the first branch (‘if’ branch); or
false - executing the code block in the second branch (‘else’ branch).
So, in my 4 examples (A, B, C and D), where I’ve said, for example:
what I actually mean, and therefore should have said, is:
First, the two comparisons evaluate to TRUE & TRUE = TRUE.
Then the!
negates this first evaluation of TRUE to give a final evaluation of FALSE, which executes the code block in the second branch (‘else’ branch).
I’d be grateful if you could still check whether my 4 examples are correct (in terms of !
position, use of brackets, and final outcome), bearing in mind this adjustment to the wording and therefore their interpretation.
If x
is 'blue'
, then ! x
will be false
since ‘blue’ is truthy. We would only NOT x if it was an expression other than a string literal. Instead, NOT the comparison expression, which will need brackets since Logical NOT has precedence to IDENTITY (Strict Equality).
! (x === 'blue')
is false
when x is ‘blue’, true
when x is not ‘blue’.
When brackets are used to group expressions, then what’s inside is evaluated first. When there are no brackets then we follow left to right associativity.
! x === 'blue' =>
false === 'blue' ? false
Not so. As we’ve shown they both result in false
but not for the same reason.
! x
short-circuits AND so the second operand is not evaluated.
! (A && B)
is false
because it negates the full evaluation of both truthy operands with AND.
In your example B, again, it is not the same reason. ! x
is false
when x is truthy. That short-circuits AND.
We say the F && F
is false
, but in truth, F && anything
is false
since anything
never gets evaluated when the first operand is false.
In C, not truthy && not truthy short-circuits. We never get to the second operand. If expression A is truthy, we never look at expression B.
In D, both expressions will be falsy, so NOTting both will make them both true
. We’ve already seen that,
! A && ! B
is the same as,
! (A && B)
Thanks so much for that analysis @mtf… I’ve managed to follow it through and I’m now clear about my examples A, B and D
Can I just query your explanation of my example C?
Shouldn’t this be:
-
(not truthy && truthy) short-circuits… as
!(y > 5)
is NOT(falsy) i.e. truthy? -
But as you say we never get to the second operand anyway… but because the first expression is not truthy, because if it were truthy, then with an
( && )
statement we would have to evaluate the second operand to see if it were also truthy.
Is this correct?
Correct.
Recall that ! A && ! B
is the same as ! (A && B)
, in which case there would be no short-circuit. But when written as,
! A && ! B
it short-circuits when A is truthy. A
must be falsy for ! B
to be evaluated. If B is falsy then ! B is true
, and the final resolution of the two is true
.
Note that the outcome of A && B
is literally, B when A is truthy.
6 && 7 // <- 7
How’s that for derailing the boolean train?
7 && 6 // <- 6
Go back and read that sentence again, just to cement the logic of it. We kind of need to go down this rabbit hole to really get a picture of what truthy and falsy are all about. It also reveals more insight into what AND and OR represent as operators.
Consider the following piece of code…
const maximize = (a, b) => a > b && a || b;
What do you suppose it is doing?
Coach Hitchcock of the Edmonton Oilers…
“You don’t take your skill for granted, but you trust your work…”
You’ve lost me in the second half of your post… I think derailing boolean trains is beyond my reach at the moment… maybe I’ll be ready to go down that rabbit hole in a few weeks time after some more basics (I only started with JavaScript on Saturday as a complete beginner)
Just to clarify, when you say…
…do you mean they both evaluate to an outcome of false, when…
A = true
and
B = true
because:
(!A && !B)
short-circuits at the first operand (!A
) because this evaluates to NOT true
i.e. an outcome of false
and
(! (A && B))
- evaluates the
(A)
within the brackets to true, so doesn’t short-circuit, and next - evaluates the
(B)
within the brackets to true - which is then negated by the
!
(outside the brackets) giving an outcome of false…?
I assume you aren’t referring to my example of:
because wouldn’t that mean…
if
A = x = 'blue'
and
B = y = 5
then
(!A && !B)
still short-circuits at the first operand (!A
) because this evaluates to NOT true
i.e. an outcome of false
but
(! (A && B))
gives a different outcome…
- it does still evaluate the
(A)
within the brackets to true, so doesn’t short-circuit, but next - evaluates the
(B)
within the brackets (y > 5
) to false (becauseB = y = 5
) - which is then negated by the
!
(outside the brackets) giving an outcome of true …?
Quick reply:
A and B in my pseudo code are expressions.
A = x === 'blue'
B = y > 5
In the above real code they still represent expressions. Lock in on that.
The =
operator is right to left associative so reads from the right. 5
is assigned to y
, and the reference is assigned to B
.
I just want to clear something up. !A && !B
is not equivalent to !(A && B)
.
!A && !B
is true only if both A and B evaluate to false. !(A && B)
is true if either A or B evaluate to false.
!A && !B
is the equivalent of !(A || B)
, both in truthiness and the short-circuit evaluation that mtf is talking about.
Symmetrically, !(A && B)
is equivalent to !A || !B
. This is called de Morgan’s Law.
Thanks for that bit of clarity, and for setting us straight. I was hoping somebody would come forth to refute and untangle any incorrectness by digging deeper into the logic.
This makes more sense to me, and is more along the lines of what I was trying to question above.
Can you confirm that the following is therefore correct?
Note: As with my original example, each of the following statements are based on the variables x and y having already been assigned values as follows:
let x = 'blue';
let y = 5;
FIRST FACT
!A && !B
can have the same outcome as !(A && B)
, if both A and B individually evaluate to the same (i.e. BOTH TRUE, or BOTH FALSE) as shown in examples 1a and 1b:
Example 1a
if (!(x = 'blue') && !(y <= 5))
This statement is !A && !B
A evaluates to true
so
!A evaluates to false
so short-circuits, and B not evaluated
Outcome of if (statement) is FALSE
Example 1b
if (!(x = 'blue' && y <= 5))
This statement is !(A && B)
A evaluates to true
so doesn’t short-circuit, and
B evaluates to true
so
A && B evaluates to true AND true = true
so
!(A && B) evaluates to false, and
Outcome of if (statement) is also FALSE
Example 1a evaluates to FALSE
Example 1b evaluates to FALSE
However,
SECOND FACT
because !A && !B
can have a different outcome to !(A && B)
, if A and B individually have differing evaluations (i.e. TRUE/FALSE or FALSE/TRUE) as shown in examples 2a and 2b:
Note: the only change to expressions A and B in the if(statement) is that now B = y > 5
(instead of y <= 5
); expression A remains unchanged.
Example 2a
if (!(x = 'blue') && !(y > 5))
This statement is !A && !B
A evaluates to true
so
!A evaluates to false
so short-circuits, and B not evaluated (as in example 1a above)
Outcome of if (statement) is FALSE
Example 2b
if (!(x = 'blue' && y > 5))
This statement is !(A && B)
A evaluates to true
so doesn’t short-circuit, and
B evaluates to false
so
A && B evaluates to true AND false = false
so
!(A && B) evaluates to true, and
Outcome of if (statement) is TRUE, which is different to example 2a.
Example 2a evaluates to FALSE
Example 2b evaluates to TRUE
I hope I’ve managed to explain more clearly and logically what I’ve been trying to understand.
When my brain’s recovered a bit, I’ve take a dive into De Morgan’s Laws !
Thank you both @mtf and @chrisgallegos for your help and patience!
The “rabbit hole” I mentioned was brought up so we would eventually unearth any inconsistencies through testing and observation.
Recall the earlier statement,
A && B
returns B when A is truthy, else it returns A.
0 && 7 => 0
7 && 0 => 0
! A && ! B
when A is 0 and B is 7 returns a boolean since we are ANDing two booleans. Recall that !
first casts to a boolean then toggles it. !A
will be true
so the yield will be !B
, or false
.
! (A && B)
when A is 0 and B is 7 returns a boolean since it casts the yield to a boolean and toggles it. The yield as shown above will be A. Then we NOT it…
! 0 => true
Similarily,
A || B
returns A when A is truthy, else it returns B
0 || 7 => 7
7 || 0 => 7
! A || ! B
, as stated will return a boolean since we are ORIng two booleans. Since ! A (A is 0) is truthy (in this instance), then ! B is is not evaluated, and the yield is true
.
! (A || B)
returns a boolean since we NOT the yield of A || B. A is falsy, so we yield B, and NOT that…
! 7 => false
So we can see that
! A && ! B === ! (A || B)
when A and B are opposite.
What about when they are both the same.
! 6 && ! 7 => false
! (6 && 7) => false
! 6 || ! 7 => false
! (6 || 7) => false
As this begins to make sense, you will be able to explain,
const maximize = (a, b) => a > b && a || b;
Mind, if not already covered, do the unit on Functions before attempting to.