Understanding the NOT operator!

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?

1 Like

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

4 Likes

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.

1 Like

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…

:joy::rofl::joy::rofl:

… 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’ :wink:

1 Like

But they are both truthy, so not much difference.

1 Like

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)

Found this table on MDN

Operator precedence

1 Like

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 :smiley:

Can I just query your explanation of my example C?

:thinking: 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?

1 Like

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) :wink:

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))

  1. evaluates the (A) within the brackets to true, so doesn’t short-circuit, and next
  2. evaluates the (B) within the brackets to true
  3. 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…

  1. it does still evaluate the (A) within the brackets to true, so doesn’t short-circuit, but next
  2. evaluates the (B) within the brackets ( y > 5) to false (because B = y = 5)
  3. which is then negated by the ! (outside the brackets) giving an outcome of true …?

:crazy_face: :sweat_smile:

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.

5 Likes

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.

1 Like

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 ! :muscle:

Thank you both @mtf and @chrisgallegos for your help and patience! :smiley:

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.

1 Like