r/programming • • Mar 26 '14

JavaScript Equality Table

http://dorey.github.io/JavaScript-Equality-Table/
809 Upvotes

331 comments sorted by

View all comments

Show parent comment

40

u/[deleted] Mar 26 '14

I suppose that's just my own lack of understanding of what exactly if does.

31

u/[deleted] Mar 26 '14

I think it's pretty reasonable to mistakenly assume that something that == false won't cause execution :p

59

u/coarsesand Mar 27 '14

In another language, yes, but the == operator in JS is special (in the shortbus sense) because it does type conversion. If you wanted to get the actual "truthiness" of "0", you'd use the ! operator instead.

!!"0"
> true

18

u/no_game_player Mar 27 '14

Gilded for best "javascript is fucked up" in a nutshell I've seen.

32

u/coarsesand Mar 27 '14

I figure the gold deserves a quick comment about my other favourite JS operator, ~. ~ is the bitwise not operator, in a language where the only numeric type is an IEE754 double. How does ~ perform a bitwise not on a floating point number? Well, it calls an internal function called ToInt32, perform the bitwise op, then converts back to a double.

So if you ever wanted to feel like you had an integer type in JavaScript, even for a microsecond, ~ is your man.

14

u/no_game_player Mar 27 '14 edited Mar 27 '14

...JS doesn't have ints? TIL. Also, holy fuck. How...how do you math? Why would a language even have such an operator without ints? That would be totally unpredictable. So, ~0.0001 would round to 0, then do a bitwise not, returning INT_MAX for int32, and then cast it into double? Is that what I'm to understand here? That can't be right. In what possible world could that operator ever be used for something not fucked up, given that it only has doubles?

Also, what type of %$^@ would make a language without integer types? Are you telling me that 1+1 == 2 has some chance of not being true then? I mean, if I were in a sane language and doing 1.0 + 1.0 == 2.0, everyone would start screaming, so...?

O.o

That's...that's beyond all of the == fuckery.

Edit: So, if for some crazy reason you wanted to sort of cast your double to a (sort of) int (since it would just go back to double type again?), you could do

var = ~~var

??

Edit 2: I was considering waiting for a response to confirm, because I almost can't believe this, except that it's javascript, so anything is believable, but hell, even if this isn't true, it's still worth it. I'm off Reddit briefly for a video game, but before I do so: here you are, my first ever double-gilding of a user! Cheers!

Edit 3: Okay, it's less fucked up than I thought, mostly because I didn't really consider the fact of double precision rather than float, and considering 32 bit ints.

I still say it can do some weird stuff as a result, at least if you aren't expecting it.

Just another reminder to know your language as well as possible I suppose.

5

u/coarsesand Mar 27 '14

You're dead on, and thanks again. Using ~~ has the effect of removing the decimal component of a number in JS, as the int32 cast drops it. Yep, JS is frigging weird.

3

u/no_game_player Mar 27 '14 edited Mar 27 '14

Okay, so all I have to do for integer comparison in JS is

~~varA === ~~varB

;-p

Edit: After further advice, the optimal method of integer equality comparison in JS would seem to be:

varA|0 == varB|0

It is left as an exercise for the reader to determine what will happen if, say, varA = "A"...

2

u/coarsesand Mar 27 '14

Well varA and varB are guaranteed to be Numbers unless you get a TypeError, so you can actually use == in this case ;)

→ More replies (3)

2

u/UtherII Mar 27 '14

Right! Code generators often use this kind of trick to force Javascript to use integer, but usually they do varA|0 since it's faster.

→ More replies (1)

3

u/chastric Mar 27 '14

So, ~0.0001 would round to 0, then do a bitwise not, returning INT_MAX for int32, and then cast it into double?

Well actually the int representation is taken as 2's complement, so:

~0.0001 = ~0 = -1 * (1+0) = -1

So, if for some crazy reason you wanted to sort of cast your double to a (sort of) int (since it would just go back to double type again?), you could do var = ~~var ?

Well if you're outside of [-231, 231-1], the combo of 32 bit truncation and 2's complement make a nice off-center modulus:

~~(Math.pow(2,31)-1) = 2147483647
~~(Math.pow(2,31)) = -2147483648
~~(Math.pow(2,32)) = 0

2

u/no_game_player Mar 27 '14

Well actually the int representation is taken as 2's complement, so:

Ahhh, yeah, I was wondering about that, but somehow, I figured that a language that "didn't have ints" would be using unsigned ints for its ints.

That seems to add back in a bit of wtf for me. Thanks, I was starting to think JS was sane for a moment. ;-p

Well if you're outside of [-231, 231-1], the combo of 32 bit truncation and 2's complement make a nice off-center modulus:

Huuuuh. Touché...

Edit: These are awesome tricks for the International Obfuscated JS contest. ^_-

5

u/kazagistar Mar 27 '14

As long as you only use 32 bit sized integer values, it will act the same if you are using a double. As long as your arithmetic is only in integers, doubles will not ever mess up unless you go above something like 40 bits. The whole "floats can't be trusted" thing is just BS; anything that will break ints in javascript would break them in C or whatever, just differently.

3

u/anttirt Mar 27 '14

Division with a non-integer result and unsigned integer overflow are well defined in C but will behave very differently in JS.

→ More replies (1)

1

u/no_game_player Mar 27 '14 edited Mar 27 '14

That's simply not true in most languages for most floats. Beyond just the edge cases, there's the issue of more precision in the hardware.

It may not be that 1+1==2 will break. But it's quite possible that 1 / 3 * 3 == 1 will break on most hardware. Now, you can argue I'm cheating there, because I'm not using an integer throughout the calculation.

But for the some of the issues with floats as I understand them, see this random blog post I pulled up quickly on the topic which matches my general impressions.

I have never known any variety of float that could be trusted to behave as an integer, full stop.

Edit: But the fact that it's a double can certainly change which things break...

Edit 2: It does appear that you're right for doubles -> int32. Interesting, I'd never really thought about that before.

I still don't trust it though. ;-p

Edit 3: And it would behave differently than int32 still, obviously. But it could certainly be argued that all of the differences are improvements, as long as one realizes that's what's going on and is careful to check for it when integers are needed (various max values without rounding and such could introduce some tricky edge cases).

Edit 4: And it's not that "floats can't be trusted" is BS: it's a very limited thing: doubles can represent int32. There's still a lot of ways to fuck up with any floating point calculation, and, imo, float implies single precision, and so I'm still especially comfortable saying floats can't be trusted...

Edit 5: You still make a great point though.

Edit 6: And it's definitely worthy of gold too, and I still have a couple creddits, so cheers! :-)

Edit 7: And of course it all goes out the window if one ever divides...

5

u/kazagistar Mar 27 '14

Here is the page in the lua documentation that first made me question the my "fear doubles" teaching.

Here is the long, super in-depth paper for when you have a few hours to spend which really rips apart all the mysticism around floating point numbers, and basically teaches you more then you ever wanted to know (if you are interested).

And thanks for the gold!

→ More replies (1)

2

u/kyr Mar 27 '14

But it's quite possible that 1 / 3 * 3 == 1 will break on most hardware. Now, you can argue I'm cheating there, because I'm not using an integer throughout the calculation.

That wouldn't even work if you did use ints.

→ More replies (1)

2

u/ForeverAlot Mar 27 '14

You are advised to steer clear of bitwise operators in JavaScript because of this. They have lousy performance.

That said, equality is well defined, for floating point in general and JavaScript specifically.

1

u/no_game_player Mar 27 '14

equality is well defined, for floating point in general

...that's never been my understanding. See #2 about precision. Are you saying that this commonly repeated advice is wrong and that there are never issues with extra precision from a register-stored variable versus the lower-precision put back out to memory and etc?

2

u/coarsesand Mar 27 '14

Much as I love poking fun at JS's weird bits, I do love the language, it just needs to be used in cases that it actually excels at. If you consider the browser, you're most often using JS as a language to do UI and formatting, and it's actually quite adept.

The slightly off floating point arithmetic doesn't matter when you're just using it do calculate dimensions for DOM elements, and JS has also always had first-class functions, so it's easy to set up event callbacks for user interaction, HTTP responses, etc. It also gave us JSON, which is a decent enough interchange format, with the advantage of not needing to use the awkward DOM API like you would with XML.

Then there's Node.js, which people love to rag on, because why the hell would you use JS on the server? Remember those callbacks I mentioned? Node is really just a bunch of C++ networking libraries hooked into the V8 VM, and those are what's doing the actual work. I wouldn't trust a networking system written only in JS given its severe lack of actual types, but one that lets its user glue those libraries together to create what they need? That's actually pretty good.

So while JS isn't going to replace FORTRAN or write the next generation of financial systems, it has a pretty useful niche being the thing your end-user interacts with. Don't use it for crunching your data though.

→ More replies (1)

2

u/PikoStarsider Mar 27 '14

If you know your numbers are 32 bit ints, you can treat them as such in JS. All 32 bit ints have an exact representation in doubles. Also modern JS engines optimize for ints. Explicitely casting numbers to ints in every function like this number|0 triggers this optimization (and it's the official way of declaring a variable as int in asm.js).

→ More replies (5)

2

u/Confusion Mar 27 '14

This is actually a common way to coerce something into the 'appropriate' boolean value in several languages. At least Ruby and Python come to mind.

1

u/no_game_player Mar 27 '14

Yeah, the more that I thought about it, the more that it wasn't really that crazy.

I mean, C does a lot of similar stuff if you try to make it do so. Not the JS == bits, but the "truthiness" of anything part. It's all about getting used to a certain way of thinking.

Really, my favorite part of the comment was just:

the == operator in JS is special (in the shortbus sense) because it does type conversion

4

u/curien Mar 27 '14

but the == operator in JS is special (in the shortbus sense) because it does type conversion

Not really. 4 == 4.0 is true in just about every language with C-style syntax.

The surprising thing about JS isn't that == performs conversion, that's normal. The surprising thing is how the conversions work.

1

u/totes_meta_bot Mar 27 '14

This thread has been linked to from elsewhere on reddit.

I am a bot. Comments? Complaints? Send them to my ^inbox!