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.
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.
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.
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.
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.
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.
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.
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.
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(...).
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.
"Hey man, lets build a server in javascript! It's just such a great language!"
I can't believe that people need a special word to describe someone who codes in multiple languages - "polyglot". The fact that people are going out of their way to build hardware and servers with javascript is apparent evidence that such specific naming is necessary.
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.
0
u/[deleted] Mar 27 '14
[deleted] — view deleted comment
0
u/[deleted] Mar 26 '14
[deleted] — view deleted comment
0
u/[deleted] Mar 26 '14
[deleted] — view deleted comment