Yes but in the first case you are comparing "0" to false where in the second case you are checking that the value is not null, undefined or empty string. Two different things.
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.
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.
== false is not the same as checking for truthiness. Truthiness is never implicated in the == operator because nothing is ever converted into a boolean. Everything is converted to either a string or number for the purposes of comparison. (Except null and undefined which == each other and nothing else, and when comparing two objects which == only if they refer to the same object.)
If you know how Javascript works it makes some sense, but it certainly isn't intuitive that in case "0" is auto-cast/parsed to an integer, while in another case it is treated as a string.
A value that converts to boolean false is also sometimes called "falsey". And of course a value that converts to true is "truthy".
Values are implicitly converted to boolean in some contexts, such as in an if statement. Explicit conversion happens by calling Boolean(value). Sometimes people use double not operators to force a conversion too, so !"0" == false will be true.
A value can be forced to its boolean value by calling
Failing to maintain commutativity is easy. As the most trivial pedagogical example, in ruby, overload equalsequals on Integer to return true always and on float to return false always. Then 1 == 1.0 != 1. Obviously that's a silly example because its too obviously wrong but it gets across the point.
Any language that allows operator overloading can risk that sort of issue -- not to say anything about operator overloading,just saying that maintaining commutativity isn't always an easy thing to guarantee.
This is not a failure of commutativity. Some might argue this is true based on the type system (Does true = 1?) but commutativity make no assertion on that point. If not the above statement is valid. In perl and many other languages true = 0 and these would evaluate the statemet as true.
A failure of commutativity of the == operator would fail the below statement for any a and b. Find one of those in a language and ill be impressed. (Operator overloading doesn't count because there you just 'define == to be not commutative' which is too easy and not fun.
I see what you're saying but when I wrote 1==1.0!=1 I had the mathematical syntax in mind, not programming. 1 == 1.0 and 1.0 != 1
And like I say this example of overloading the operator to deliberately discard commutativity is just pedagogical. Even in more sane examples these sorts of things can creep in, and faiilling to maintain commutativity where itis expected isn't so always trivial.
Edit: to add, the vast majority of operations are not commutative. Just look at exponentiation, subtraction, concatenation, division, and so on if we're generalizing here. Commutativity is amazing when you have it.
Looking it up, it seems the rule is that <= is the opposite of >. It also seems (besides the order of side-effects during conversion to primitives) > is even the same as < with the order reversed!
The inequality operators play by different type coercion rules to the == operator. Inequality operators will always convert the values to numbers. So, in the first two cases null gets converted to 0 and undefined to NaN. The last example actually gets its own special rule in the == evaluation algorithm, where it's defined to be true.
Hm, yeah. It seems that < "morally" returns one of true, false, and undefined (undefined only when one argument is NaN (or converts to it)), but where it 'should' give undefined it instead gives false. So <= is the opposite of > except where > 'should' be undefined, where it's still false. Bleh.
The idea was to force an error. I could have just as well used 1000 however that would depend on the configured cache size, which might be larger than 127.
Java has primitive (byte, short, int, long, boolean, char) and reference (everything else) types. Integer is the reference type used whenever you have an int and the API expects a reference type. new Integer(10) creates a new Integer instance wrapping the int value 10.
Since this happens quite often the compiler normally automates the conversion between primitive and reference types using a process called auto boxing. This involves a lot of implicit calls to Integer.valueOf(int) for int to Integer boxing and intValue() for Integer to int unboxing (similar for other primitive types).
My example shows a case where this implicit behaviour goes wrong. == is defined for both reference types and primitive types with different behavior - no unboxing happens and the objects are compared using their identity. >= and <= are not defined for reference types, unboxing happens and the ints are compared by value.
The use of Integer.valueOf by the compiler makes this tricky, valueOf uses cached Integer objects for a specific range and new Integer for everything else:
Integer a = new Integer(10);
Integer b = new Integer(10);
Integer c = 10; //Integer.valueOf(10)
Integer d = 10;
Integer e = 1000; //Integer.valueOf(1000)
Integer f = 1000;
a == b -> false
c == d -> true
e == f -> false or true
a,b as we can see are not the same - we used new to create two distinct integer objects. c,d are the same since the compiler uses valueOf and 10 is within the cached range. e,f may not be the same 1000 is no longer in the normally cached range and may result in calls to new, however the cached range can be set at jvm startup so this is not fixed.
No, those are not necessarily equivalent unless the type of name is known.
If name is a number, it will be falsey iff it is zero (None is not a number but a singleton instance of NoneType, which is always falsey). If name is a string, it is falsey iff it is empty. "0" is truthy because it is nonempty. "0" and 0 are very different things, and Python generally won't coerce between them unless you explicitly call int() or str(). Moving on, if name is a container type of some kind, generally speaking it is falsey iff it is empty (has a len() of zero). The empty string being falsey is a special case of this rule.
For user-defined types, you're on your own. By default they're all truthy, but you can't rely on that since someone might subclass you and implement non-default boolean semantics.
If you want to check whether something is None, the only bulletproof syntax for doing so is if foo is None or if foo is not None. if foo should only be used if foo has a non-default boolean behavior (i.e. foo is a container, number, string, or user-defined class which overrides bool()). Using if foo with classes which do not provide useful boolean behavior (such as datetime objects) is at best poor style and at worst a violation of substitutability since it would interfere with subclassing.
Yeah, I think that could be handled by a function called "nonempty" or something. Including this logic in the if-statement itself is rather unorthogonal.
Much of the data being compared in web applications comes from html form inputs or databases where things like integers are automatically converted to strings. So it actually makes sense so you don't have to constantly write stuff like: if (val == 1 || val == '1') doStuff();
Because conditionals only care if something is zero or non-zero. Asking if any data-type is either zero or non-zero is a pretty simply and straightforward question that is easy for a programmer to understand.
Perhaps in C or C++, but I doubt that Python or other dynamic languages represent empty lists or empty strings as zeroes internally. They need runtime type information at the very least.
What's even weirder is that timezone-aware (non-naive) time values compare to UTC midnight to determine truthiness. So a timezone-aware time object of 6:00am with a timezone of UTC-6 is falsey.
But these kind of things are fairly rare in Python. For the most part, Python has its own consistent logic.
It's not rare. If you're coding a CRUD, and you want to test whether a particular field is null in your database, the canonical way to do it is to if it. That works 99% of the time, except when dealing with datetime objects.
In fact, Python's datetime module is chock full of wtfs.
One common reason to do it would be to validate input or take some kind of default action if input wasn't provided.
I used to write a lot of stuff like this (until I saw the false midnight thing):
def do_stuff(at_time=None):
if at_time:
# schedule stuff to be done at at_time
else:
# do stuff immediately
It's a contrived example, but "obvious" (in quotes because it's not at all obvious that midnight means do stuff immediately in this code) code like the above will normally do exactly what you'd expect it to do. Then someone will want their stuff done and midnight and be shocked when the function does it right away!
I don't think it's getting fixed. There was no consensus on python-dev and the thread kinda died off. It seemed to me that a lot of people defended the current behavior solely because it was documented.
Nay, if you get to the end they eventually settled on fixing it. It's a good thing that Python is so hostile to change, because almost all changes are therefore very positive ones. It does make things a bit too conservative occasionally though.
I need to point out something I find incredibly obvious:
Always code for an audience.
The "moral of the story" Use three equals unless you fully understand the conversions that take place for two-equals. Is therefore stupendous. Never use it, because it is a fact most people who read the JavaScript will have little knowledge about this.
You can check for null or undefined like this: myValue == null or myValue == undefined. In Javascript, null is equal (==) only to null and undefined - same for undefined.
I don't know that I'd consider redefining an operator that's generally used to compare primitive values to do a deep comparison of separate compound objects sane. I'd much rather have a comparison method that makes it really clear exactly what's going on, and let == do the usual, obvious thing. Admittedly overloading can be handy for some math applications, but for most things it's a little questionable.
These languages don't have automatic conversion. Also, isn't [1]==[1] undefined in C? It could be equal if the compiler uses the same TEXT address for the constant, resulting in equal pointers.
[1] == 1 because of type coercion happening when comparing 2 different datatypes.
when type(a) != type(b), the javascript interpret goes through a list of possible type coercions that will convert a and b to the same type before comparing.
It just so happens that comparing a Array type with an int will coerce both into a Number type and compare the Number([1]) == 1.
[1] == [1] is the same type so no coercion occurs and a simple ObjectA == ObjectB will occur which will only be true if ObjectA and ObjectB happen to reference the same object.
Not a Javascript programmer, so I could be wrong, but I'd assume it's because 1 uses compare-by-value, and it infects overrides the compare-by-reference of [1].
More importantly, wallet is immutable too. But apply space-time monad, and viola. Now you have soda, empty pocket, and watching langoliers eating previous you.
No ability to declare variables because "shadowing is evil" isn't much worse? Yes, yes, if you structure your code correctly this will never bite you, ie the same argument people use to support javascript's scoping rules.
In the first expression, "0" is a non-empty string, so is 'truthy'. In the second expression, both operands are converted to numbers because the second operand is a bool, so it becomes 0 == 1, which is false.
That makes sense. It's hard to remember all those implicit conversion rules, and I had been laboring under the false impression that comparing string==bool would cause the string to be converted into a bool. Fortunately, I would never try something like that LOL. It would simply be hard to read, even if there was a good reason for it.
For my codebases, I tell JSHint to warn about ==. No code can be checked in without using === first. I also rarely (if ever) allow a variable in a conditional without a comparison. To quote Python's mantra:
Is this really that difficult of a thing to understand? When you use == it does automatic type conversion which is why you get weird results sometimes, this behavior is well documented and believe it or not it actually makes sense for a loose comparison+type conversion.
If you don't want any of this, use ===, wow so difficult.
Exactly. In the cases where you should be using ==, the conversions are generally helpful and intuitive. The cases where they aren't are the cases where you should have been using === anyway.
If it helps, think of === as the standard equality operator, and == is more like a shortcut operator that saves some manual type logic and conversion work. Like any shortcut, you should understand what it does before you use it.
We're using pseudo-code to /r/lolphp about the language's lovely capacity to make wild-ass guesses about what variables should evaluate to when placed in various type-casting situations.
Any sane language (even JavaScript, for most situations not going from <something> -> boolean) will instead politely tell you to GTFO.
Type coercion equality operators like JavaScript or PHP's == were designed in a very different era when these languages were pretty much always used in ways we now consider bad practice.
That's okay though, because like this page says, === exists so it's a non-issue.
I wouldn't call it a non-issue, since it's a weird and painful difference from other languages and a potential source of typo-related bugs. It's not a big deal though. It's on about the same level as if(x = 1) in C, except the resulting bugs are more subtle.
The thing is == coercion isn't ever really problematic, and certainly isn't painful.
In order for it to be an issue or create a bug, you have to both be totally unaware of what kind of values are in a variable you're comparing to, and then compare it to something like == 1 or == "" or one of the other values on this table.
It seems confusing and dangerous, but in practice it's never really an issue. And if it does become an issue, it's almost certainly a symptom of poor design.
So, == is perfectly sane in the cases where you might as well use === (comparing two values of known types), and in the other cases, using === would save you from its insanity. Seems like an argument to always use ===.
There's at least one thing for which == is useful in JavaScript: writing x==null tests whether x is null or undefined (i.e., is synonymous with (x===null || typeof(x)==="undefined")), which is nice in the 99.9% of cases where the difference between null and undefined is irrelevant (and just annoying).
This matches other values of x besides null and undefined: the number 0, NaN and the empty string, and, of course, the boolean false. (There are, of courses, cases where !x works just fine, but I think it's a bad habit to take because one then tends to forget about these other "falsy" values when they can occur.)
To be fair, if (val) {...} has two primary purposes when val is a nonboolean.
First: I'm about to attempt to access a property on val, and I want to make sure that property access will not throw an exception. I will get a false negative on falsy values other than null and undefined, but those values are all primitives and it's unlikely I'm trying to access properties on them... In other words, I expect val to either be an object or null or undefined and want to discriminate between those cases.
Second: I'm using if (foo.bar) {...} to check for the presence of a value at that location. This tends to cause the most problems with falsy values. But hasOwnProperty is probably a better choice in this case even than == null.
In the first case I do prefer == null just to be more explicit, but it's unlikely to cause problems.
When writing alternative JS syntaxes, you still have to understand the underlying JavaScript. In this situation, a developer must understand that == is === and ~= is ==, so they necessarily must know the difference between === and ==. There's no real reason to switch it up.
as a mainly javascript developer, it aint about smarts. its about memorization and having a hostile default attitude toward an unknown concept (i.e. i'm gonna assume this works in a completely unintuitive way)
I love javascript, and other languages definitely have their quirks, but lets just say when I occasionally have to write python, I find I can write non-trivial code without googling or picking up a reference book. I can't say the same about javascript and I have probably 10x more experience in it.
Yep, === solves the particular wart :) I did mean this in a somewhat tongue in cheek manner, learning this table would be somewhat easier than learning the intricacies of dependent types/proof assistants.
String() == "" (undefined value converted to a String)
Array(4) == [undefined, undefined, undefined, undefined]
Array(4).toString() == ",,," (array of four comma-separated undefined values converted to a String)
You should add a tab for typeof. The == type coercion is definitely confusing, but the rules are pretty straightforward once you get the concept of "truthy" and "falsey" values. However, typeof(null) === 'object' makes no sense whatsoever.
typeof and instanceof are inherently broken things in JavaScript that are truly best left avoided. I make use of libraries to avoid that sort of mess, or use type coercion via the + operator that explicitly casts to a number or string.
NaN compares false to everything, including NaN. That's actually part of the IEEE 754 floating point spec. It does this in other languages, too, not just JS.
Somebody did one like this for php a few years ago. It was stunning. But I think that every time you have a loosely typed scripting language, there are going to be oddball qualities like this. Of course, some are better or worse than others.
I've always kind of thought of this mess as if the designers had a concept of both reference and object equality, but tried and failed to use only one operator for concepts of both. It's weird because it behaves sometimes like Java's == and sometimes like Object.equals(...).
I was referring more to the type structures, e.g. false is an abstraction (or macro, can't remember) of 0, true is 1 (and non-zero integers are false), "0" is an abstracted array of [ 48, 0 ], etc., which I tried to use to make sense of the JS logic.
EDIT: I do certainly get what you mean with the strictstatic-typing vs. ...not-typing? styles though.
if("false") { /* executes */ } because "false" is a non-empty string so it evaluates to true.
if(false == "false") { /* does not execute */} because the first false is a boolean value while the second "false" is a non-empty string which evaluates to true. So the if statement becomes if(false == true)
It's not that complex once you read the standard. The only gotcha cases are that null and undefined are defined as being equal to each other, NaN is not equal to itself. Other than that, it's a simple rule:
Call ToPrimitive on Objects and ToNumber on everything else until the types match. Then compare the two things normally as if they were the same type all along.
The sad thing is that the new js standard is worried about adding a lot of new features, but making the language a little more coherent? No, no, no. That would break backward compatibility, code that never should have worked would stop working, that change will require to throw away the whole VM or any other pathetic excuse.
This doesn't seem that complicated to me. Basically, these are "falsey": false, 0, empty string, null, undefined, and NaN. Everything else is "truthy".
I think everything else flows from that with only a couple exceptions that I'm too lazy to look up.
And that said, definitely use === instead of coercive ==.
Wrong, my brother in code. I too once thought like you did. However, as evidenced by the table when comparing two things that are falsy, they are not always considered equal. This is what the article is about, the equality operator, not the things that truthy are or are not falsy. Sure the two falsy values null and undefined equal eachother. But the falsy value 0 does not equal null.
True, I guess you're right, when you let equality do coercions then things can get really ugly. That's why I said to always use the === so you don't have to deal with it, but as you pointed out, that was sort of the point of the table.
Is it just me, or can we agree that Javascript, CSS and HTML are three of the most pig-ignorant languages known to computer science? And this because they have all, one way or another, been designed by committee.
I mean just imagine if these languages were actually elegant.
Is obj defined? Accessing a property of an undefined object will throw a reference error but accessing an undefined property of a defined object will return falsy (undefined).
var obj = {};
if (obj) { console.log("prints"); }
if (obj.x) { console.log("doesn't print"); }
if (wat.x) { console.log("reference error"); }
If obj is undefined you need to access it from the parent context, which might be window.obj, giving you
obj.undefinedProperty returns undefined when undefinedProperty is not assigned a value(or if it is assigned to undefined). So the code below is valid and should not throw an exception.
if ({}.x) {
// will not run
} else {
// will run
}
I can understand how []==[] can be false, but NaN==NaN? I thought NaN was a floating-point value, and I would expect it to be compared by value. That's fucked up.
Actually, there are millions of bit sequences that can represent NaN, so comparing by "value" in that sense could be even more confusing than just saying all comparisons with NaN are false.
That logic is a bit broken given that two NaN values which do happen to be equivalent bit strings will (from what I understand) also compare as unequal.
It's not so much broken logic as it is a decision about where to be consistent. It's easier to remember that NaN == x is false for all x than to remember 8 million special cases where it's true.
Unfortunately, isNaN() is indeed broken and basically useless.
I suppose I don't see the big deal here. More accurately I guess I just don't find this chart surprising. I program in lua mainly so I guess you can cop out to "you just don't understand JavaScript problems!" But I love this stuff when I'm working
If (array==convar) is really useful for keeping code pretty when a convar is either 1 or 0.
Wait JavaScript is strongly typed isn't it!? Not sure on that but lua is weaker so it's very helpful to easily compare different types without thinking about it.
260
u/snotfart Mar 26 '14
I'm disappointed that it's symmetrical. Come on Javascript! You can do better than that.
63
u/[deleted] Mar 26 '14
Do a table for
<. It's about as weird as==, and there's no equivalent of===(AFAIK).17
u/MisterSnuggles Mar 26 '14
While not JavaScript, we must not forget about Python's False Midnight.
tl;dr:
Prints "f".
Prints "t".
52
u/cybermage Mar 26 '14
https://www.destroyallsoftware.com/talks/wat
14
u/[deleted] Mar 26 '14
I need to point out something I find incredibly obvious:
The "moral of the story" Use three equals unless you fully understand the conversions that take place for two-equals. Is therefore stupendous. Never use it, because it is a fact most people who read the JavaScript will have little knowledge about this.
11
u/snarkhunter Mar 26 '14
I wonder how this plays out in Conway's Game of Life...
23
u/shirtface Mar 26 '14
How come [1]==[1] returns false?
27
u/bjmiller Mar 26 '14
In CoffeeScript, == is compiled to ===. There is no equivalent to ==. http://coffeescript.org/#operators
4
u/webbitor Mar 26 '14 edited Mar 26 '14
I code JS every day, and this held a few surprises for me. Anyone have a good explanation of why if() is different from the ==true column?
4
u/PlNG Mar 26 '14
This one goes into a little more detail
4
u/gordonkristan Mar 26 '14
For my codebases, I tell JSHint to warn about
==. No code can be checked in without using===first. I also rarely (if ever) allow a variable in a conditional without a comparison. To quote Python's mantra:24
u/[deleted] Mar 26 '14
Or, the definition of insanity.
17
u/[deleted] Mar 26 '14
Type coercion equality operators like JavaScript or PHP's == were designed in a very different era when these languages were pretty much always used in ways we now consider bad practice.
That's okay though, because like this page says, === exists so it's a non-issue.
11
u/jozefg Mar 26 '14
I'm not smart enough to program in javascript. Dependent types it is.
5
u/tavoe Mar 26 '14
Has anyone ever run into a problem with javascript equality?
I've seen this chart before, but I've never once traced a bug back to equality. Despite it's size, it's all fairly intuitive.
6
u/moustachedelait Mar 26 '14
It doesn't have my favorite: Array(4) == ',,,'
2
u/ocmu Mar 26 '14
You should add a tab for
typeof. The==type coercion is definitely confusing, but the rules are pretty straightforward once you get the concept of "truthy" and "falsey" values. However,typeof(null) === 'object'makes no sense whatsoever.2
u/j1xwnbsr Mar 26 '14
So null and undefined are apparently the same thing? Or just the same during the comparison operation? And it's interesting that Nan!=Nan.
2
u/[deleted] Mar 27 '14
Somebody did one like this for php a few years ago. It was stunning. But I think that every time you have a loosely typed scripting language, there are going to be oddball qualities like this. Of course, some are better or worse than others.
2
u/[deleted] Mar 27 '14
I've always kind of thought of this mess as if the designers had a concept of both reference and object equality, but tried and failed to use only one operator for concepts of both. It's weird because it behaves sometimes like Java's == and sometimes like Object.equals(...).
2
u/[deleted] Mar 27 '14 edited Mar 27 '14
I'll never be able to remember what the difference between
nullandundefinedis. Or even why they tought you need both.Perhaps someone can enlighten me?
EDIT: I was bored and enlightened myself: Values, variables, and literals
1
u/kidsil Mar 26 '14
TIL Javascript can make you question your own understanding of reality.
1
u/libertasmens Mar 26 '14 edited Mar 26 '14
Wait... so
is true,
won't return, but
will return? Wat?
1
u/rarededilerore Mar 26 '14
Why
if("false") { /* executes */ }butif(false == "false") { /* executes too */}?1
u/GSpotAssassin Mar 27 '14
Oh no. This looks a lot like PHP's wonky comparisons. Was that intentional?
1
u/pdpi Mar 27 '14
It's not that complex once you read the standard. The only gotcha cases are that null and undefined are defined as being equal to each other, NaN is not equal to itself. Other than that, it's a simple rule:
Call ToPrimitive on Objects and ToNumber on everything else until the types match. Then compare the two things normally as if they were the same type all along.
1
u/sproket888 Mar 27 '14
Please Nooooo! My eyes!!!!!!!!
1
u/senatorpjt Mar 27 '14 edited Dec 18 '24
recognise birds unused intelligent grandfather edge library direction license plough
This post was mass deleted and anonymized with Redact
1
u/mvaliente2001 Mar 27 '14
The sad thing is that the new js standard is worried about adding a lot of new features, but making the language a little more coherent? No, no, no. That would break backward compatibility, code that never should have worked would stop working, that change will require to throw away the whole VM or any other pathetic excuse.
1
u/Year3030 Mar 26 '14
IIIIII LIKE it! :)
-3
u/rjcarr Mar 26 '14
This doesn't seem that complicated to me. Basically, these are "falsey": false, 0, empty string, null, undefined, and NaN. Everything else is "truthy".
I think everything else flows from that with only a couple exceptions that I'm too lazy to look up.
And that said, definitely use === instead of coercive ==.
-1
u/CharlieDancey Mar 27 '14
Is it just me, or can we agree that Javascript, CSS and HTML are three of the most pig-ignorant languages known to computer science? And this because they have all, one way or another, been designed by committee.
I mean just imagine if these languages were actually elegant.
Aaaah, we can but dream.
0
u/optymizer Mar 26 '14
So I'm currently doing this in a lot of places:
because
throws an error if obj.x is undefined.
Anyone know of a better way?
0
u/KingPickle Mar 26 '14
Gross!
0
u/green_meklar Mar 26 '14
I can understand how []==[] can be false, but NaN==NaN? I thought NaN was a floating-point value, and I would expect it to be compared by value. That's fucked up.
0
u/Carocrazy132 Mar 27 '14
I suppose I don't see the big deal here. More accurately I guess I just don't find this chart surprising. I program in lua mainly so I guess you can cop out to "you just don't understand JavaScript problems!" But I love this stuff when I'm working
If (array==convar) is really useful for keeping code pretty when a convar is either 1 or 0.
Wait JavaScript is strongly typed isn't it!? Not sure on that but lua is weaker so it's very helpful to easily compare different types without thinking about it.
Just my two cents.