
Javascript null surprise - gruseom
I just encountered this while tracking down a bug in some Javascript (verified in FF and IE):<p><pre><code>   null &#60; 0 || null == 0    -&#62; false
</code></pre>
but<p><pre><code>   null &#60;= 0    -&#62; true
</code></pre>
Would you expect that? I didn't. Obviously &#60;= is implemented as !&#62;. Time to look up all uses of &#60;= and &#62;= in my code...<p>p.s. Is this too trivial to post here? Too specialized? I'm curious.
======
idea
[Rhino book] > When null is used in a Boolean context, it converts to false.
When used in a numeric context, it converts to 0. And when used in a string
context, it converts to "null".

~~~
randrews
So I guess the confusing bit is that null==0 is Boolean, rather than numeric,
context.

~~~
slurpme
But isn't the context a Boolean expression, so the 0 would be converted to a
Boolean as well?

~~~
randrews
== needs two arguments of the same type. If they're both strings, it's a
string compare. If they're objects, it does whatever it does for objects
(identity, I think). If they're numbers, then it's a numeric comparison.

If it's given two objects of different types, then it has to coerce one of
them. In this case, I would expect it to coerce null to 0, then compare 0==0.

Your way would have it coerce 0 to false and null to false, so it's still
equal, but it has to coerce two things.

I can sort of see the logic in this though, since a lot of other languages
(SQL) have the rule that nothing is allowed to be equal to null.

~~~
slurpme
Yes I think you are right about that, too early in the morning for me...

Makes me wonder what the rules are for coercion though, that is does it pick
null to coerce or 0?

~~~
randrews
I just experimented a bit with Rhino ( <http://www.mozilla.org/rhino/> ) and I
got nothin'. I had thought it might be that it coerces the right hand side to
match the left's type, but it doesn't since:

null==0 || 0==null -> false

It's weird for number/string comparisons, too. "12" is greater than "102"
(lexical ordering, "2" > "0") but less than 102 (coerces "12" to number).

It seems like if one side is a number, then it coerces the other one to number
as well, _unless_ the other is null.

Which makes sense given what it was designed for, since any attribute you pull
in from a DOM element will be a string, and you want to make forgetting to
convert safe.

------
tlrobinson
How about this one...

    
    
        js> r = RegExp("asdf", "g"); 
        /asdf/g 
        js> r.test("asdf") 
        true 
        js> r.test("asdf") 
        false 
        js> r.test("asdf") 
        true 
        js> r.test("asdf") 
        false
    

Surprisingly this is not a bug, though I was certain it was at first. When
using the global flag the RegExp object will keep track of the last matching
character _position_ and start the next comparison at that position (after the
4th character, in this case) which results in this seemingly incorrect
alternation between "asdf" matching "asdf". Removing the global flag produces
correct results.

------
xirium
This is definitely on-topic. We've had JavaScript gotchas before (
<http://news.ycombinator.com/item?id=115914> ).

------
ratsbane
Interesting and not what I would have expected. I just confirmed it in Opera.
Also, null<=null is true.

You can use the following javascript link to confirm this:

(Note - I can't ever remember how to embed links properly in YC... is there a
reference somewhere?)

javascript:alert('null < 0: '+(null< 0)+'\nnull ==0: '+(null==0)+'\nnull > 0:
'+(null>0)+'\nnull<=0:' + (null<=0) + '\nnull < null: '+(null<null)+'\nnull ==
null: '+(null==null) + '\nnull > null: '+(null>null)+'\nnull<=null: ' +
(null<=null));

~~~
dreish
In Safari 3 and Firefox 1.5, at least, null == null, so I would expect null <=
null.

Both Safari 3 and Firefox 1.5 do the decidedly unexpected null <= 0 thing.

------
randrews
JSLint ( <http://www.jslint.com> ) won't catch this, either. It will complain
about using == or !=, but it doesn't say anything about other comparisons.

------
rglullis
Okay... I have another one.

In Python:

    
    
      >>> -1 % 3
      2
    

In Javascript:

    
    
      >>> -1 % 3
      -1

~~~
newt0311
That is actually an error in the python implementation. According to the
language reference: "(a/b)*b + (a%b) = a" where the (a/b) step is rounded
towards 0. This implies the if a is negative, (a%b) should also be negative.
Note that this modulus standard is also used for the C, C++, and JAVA
standard. Here, its python's mess up.

~~~
bayareaguy
_This implies the if a is negative, (a%b) should also be negative._

No, python is giving you the Modulus after division (i.e. a "distance" which
should be positive). If you interpret it that way everything is fine:

    
    
      >>> a = -1
      >>> b = 3
      >>> (a/b)*b
      -3
      >>> (a%b)
      2
      >>> (a/b)*b + (a%b)
      -1
    

Perhaps you're thinking of the Remainder?

Edit: it seems there isn't much consensus about what to do when a or b are
negative. Wikipedia gives a helpful chart here how different languages choose
to implement this: <http://en.wikipedia.org/wiki/Modulo_operation>

~~~
newt0311
True. I checked the python reference again and it re-adjusts the modulo to
have the same sign as the 2nd operand.

>>> 1 % -3 -2 >>> -1 % -3 -1

------
slurpme
How about this surprise which caught me out a couple of days ago, try:

function hello () {

    
    
        return
        {
           value : 10
        };
    

}

window.alert (hello ().value);

It burps in FF and IE...

~~~
tolmasky
This happens when putting a newline between return and any value.

This is actually a result of JavaScript's lax support of semi-colons. Semi-
colons are generally not enforced in JavaScript, but this leads to some
ambiguous cases. Your case may not seem ambiguous, but the following code
snippet will show what is actually going on:

if (i==5) return

i += 3;

As you can see, there are 2 possible meanings for this when there is no
explicit semi-colon after the return. It can either mean "if i equals 5
return, else add 3 to i" or it could mean, "if i equals 5 return i plus 3".
JavaScript does not try to discern which is "more correct" (since there are no
return types on functions so this would be a very difficult task), but rather
defaults to "floating returns" meaning "return;".

~~~
slurpme
I know, I mentioned it as the new object because it's one of the few
situations I know of where you might use a newline after the return keyword.

I understand what you mean, in this case though it would be helpful if the
interpreter detects the statement as being not reachable since it's after the
return.

