user717236
user717236

Reputation: 5039

How does !!~ (not not tilde/bang bang tilde) alter the result of a 'contains/included' Array method call?

If you read the comments at the jQuery inArray page here, there's an interesting declaration:

!!~jQuery.inArray(elm, arr) 

Now, I believe a double-exclamation point will convert the result to type boolean, with the value of true. What I don't understand is what is the use of the tilde (~) operator in all of this?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

Refactoring the if statement:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

Breakdown:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

I also noticed that if I put the tilde in front, the result is -2.

~!!~jQuery.inArray("one", arr) // -2

I don't understand the purpose of the tilde here. Can someone please explain it or point me towards a resource?

Upvotes: 101

Views: 27302

Answers (13)

Salman Arshad
Salman Arshad

Reputation: 272116

!!~expr evaluates to false when expr is -1 otherwise true.
It is same as expr != -1, only broken*


It works because JavaScript bitwise operations convert the operands to 32-bit signed integers in two's complement format. Thus !!~-1 is evaluated as follows:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

A value other than -1 will have at least one bit set to zero; inverting it will create a truthy value; applying ! operator twice to a truthy value returns boolean true.

When used with .indexOf() and we only want to check if result is -1 or not:

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* !!~8589934591 evaluates to false so this abomination cannot be reliably used to test for -1.

Upvotes: 106

panos2point0
panos2point0

Reputation: 170

I assume, since it is a bitwise operation, it is the fastest (computationally cheap) way to check whether path appears in modifiedPaths.

Upvotes: 2

p.g.l.hall
p.g.l.hall

Reputation: 1961

The tilde operator isn't actually part of jQuery at all - it's a bitwise NOT operator in JavaScript itself.

See The Great Mystery of the Tilde(~).

You are getting strange numbers in your experiments because you are performing a bitwise logical operation on an integer (which, for all I know, may be stored as two's complement or something like that...)

Two's complement explains how to represent a number in binary. I think I was right.

Upvotes: 58

Mina Gabriel
Mina Gabriel

Reputation: 25100

The ~ for all 4 bytes int is equal to this formula -(N+1)

SO

~0   = -(0+1)   // -1
~35  = -(35+1)  // -36 
~-35 = -(-35+1) //34 

Upvotes: 13

Yahel
Yahel

Reputation: 37305

There's a specfic reason you'll sometimes see ~ applied in front of $.inArray.

Basically,

~$.inArray("foo", bar)

is a shorter way to do

$.inArray("foo", bar) !== -1

$.inArray returns the index of the item in the array if the first argument is found, and it returns -1 if its not found. This means that if you're looking for a boolean of "is this value in the array?", you can't do a boolean comparison, since -1 is a truthy value, and when $.inArray returns 0 (a falsy value), it means its actually found in the first element of the array.

Applying the ~ bitwise operator causes -1 to become 0, and causes 0 to become `-1. Thus, not finding the value in the array and applying the bitwise NOT results in a falsy value (0), and all other values will return non-0 numbers, and will represent a truthy result.

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

And it'll work as intended.

Upvotes: 127

zzzzBov
zzzzBov

Reputation: 179086

~foo.indexOf(bar) is a common shorthand to represent foo.contains(bar) because the contains function doesn't exist.

Typically the cast to boolean is unnecessary due to JavaScript's concept of "falsy" values. In this case it's used to force the output of the function to be true or false.

Upvotes: 35

Engineer
Engineer

Reputation: 48793

As (~(-1)) === 0, so:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false

Upvotes: 1

LukeH
LukeH

Reputation: 269408

You're right: This code will return false when the indexOf call returns -1; otherwise true.

As you say, it would be much more sensible to use something like

return this.modifiedPaths.indexOf(path) !== -1;

Upvotes: 8

Alexander Pavlov
Alexander Pavlov

Reputation: 32286

My guess is that it is there because it's a few characters shorter (which library authors are always after). It also uses operations that only take a few machine cycles when compiled into the native code (as opposed to the comparison to a number.)

I agree with another answer that it's an overkill but perhaps might make sense in a tight loop (requires performance gain estimation, though, otherwise may turn out to be premature optimization.)

Upvotes: 3

Amadan
Amadan

Reputation: 198334

jQuery.inArray() returns -1 for "not found", whose complement (~) is 0. Thus, ~jQuery.inArray() returns a falsy value (0) for "not found", and a truthy value (a negative integer) for "found". !! will then formalise the falsy/truthy into real boolean false/true. So, !!~jQuery.inArray() will give true for "found" and false for "not found".

Upvotes: 18

Freyja
Freyja

Reputation: 40814

The ~ operator is the bitwise NOT operator. What this means is that it takes a number in binary form and turns all zeroes into ones and ones into zeroes.

For instance, the number 0 in binary is 0000000, while -1 is 11111111. Likewise, 1 is 00000001 in binary, while -2 is 11111110.

Upvotes: 6

Joe
Joe

Reputation: 15802

Tilde is bitwise NOT - it inverts each bit of the value. As a general rule of thumb, if you use ~ on a number, its sign will be inverted, then 1 will be subtracted.

Thus, when you do ~0, you get -1 (0 inverted is -0, subtract 1 is -1).

It's essentially an elaborate, super-micro-optimised way of getting a value that's always Boolean.

Upvotes: 11

Pointy
Pointy

Reputation: 413737

The ~ operator is the bitwise complement operator. The integer result from inArray() is either -1, when the element is not found, or some non-negative integer. The bitwise complement of -1 (represented in binary as all 1 bits) is zero. The bitwise-complement of any non-negative integer is always non-zero.

Thus, !!~i will be true when integer "i" is a non-negative integer, and false when "i" is exactly -1.

Note that ~ always coerces its operand to integer; that is, it forces non-integer floating point values to integer, as well as non-numeric values.

Upvotes: 10

Related Questions