Wednesday, April 9, 2014

TRIPLE EQUALS CONSIDERED OVERRATED === = :-(

So, a recent popular idea in Javascript land is that it's always better to compare values using "triple equals", ===, which won't do type conversion, over good ol' "double equals", ==.

So quick example:
  var foo = 123;  //foo is an integer
 foo == "123"; //true, foo "double equals" the string 123
 foo === "123"; //false, because they are different types

I find myself disagreeing strongly with the preference for "===", for 3 iffy reasons, and I think one good one.

1. What I'm used to

I can sound like a cranky old hack sometimes, and remembering to type === and !== seems like a pain, and just kind of looks ugly.  Moreover, I cut my teeth on loosely-typed "Duck languages" like Perl. So if I read in a string and wanted to compare it to a numeric value such as 123, I wouldn't want to fail just because they were "different things", or came from a different source.

2. How I think about Java

Java's String primitive/object has a parallel situation that is deceptively similar, with .equals() vs ==, and I think I draw a false analogy.  To whit: for Java objects, == is only true when you have two references to the same object in memory, while equals() should be true if two different objects are equivalent. So for instance,
 String foo = "bar";
 foo.equals("bar"); //of course true!
 foo == "bar"; //don't count on it, buddy

So I learned to be careful, and use the "less strict" equals() for most stuff I was interested in. This makes me nervous about ===. Like, I'm almost skeptical that Javascript
 "foobar" === "foo" + "bar";  //true (amazingly ;-)
Yeah it works, but because I think of it in terms of what it looks like in Java, I don't want to trust it.

FOLLOWUP in 2017: I just noticed that
foo == new String('foo')

but not
foo === new String('foo')
which is exactly parallel to the Java case, but arguably much less significant because String as an object is rather rare in Javascript land.


3. === is used to show off

It feels like an elitist shibboleth to me. (And yes, I love that knowing what "shibboleth" means is in itself a shibboleth.) To be fair, these people probably point to funkiness in the truthiness tables, and just odd asymmetries there, but in my heart of heart I think it's just a way for the with-it hipster coders to show they are with-it hipsters.

4. if(arg == undefined) //true for argument not passed, and null, but not for zero

Finally, this might be my most serious argument.

Say I have a function funk(arg), and returns its argument or a default of -1, if no argument is passed. (And of course it should work with 0 as a value) So:

function funk(arg){
  if(arg == undefined) arg = -1;
  return arg;
}

That works pretty well... (if I used the conditional if(!arg), that would accidentally catch 0 and return -1, and so in general I shun simple boolean expressions, preferring to check for undefined.)

So what I like about == is that is that funk(null) would be caught, and replaced with -1, but if I used === funk(null)would return null, because undefined === null is false.  (Of course, "null" and undefined are kind of odd beasts in Javascript land; some people think the "undefined" value is just an accident of history anyway.) (PS don't do stuff like using undefined as a real value, like calling funk(undefined) - that's just R,O,N,G, wrong.)

So basically, I prefer the behavior of double equals, and prefer its made up "this would fail!" arguments to the ones made in favor of trouble equals.

(Quick tip: if you don't know it already, the "console" you can get to in Chrome inspector or Firefox Firebug is great for doing this kind of little functional definition, tooling around with making and calling functions, just ignoring the page it's on. And of course it's an invaluable tool for poking around your Javascript in general.)

FOLLOWUP: A friend of mine points out "NaN" kind of messes up my simple != undefined filter, since it is defined, but probably not what we were expecting to work with what I described.







No comments:

Post a Comment