71 comments

[ 4.0 ms ] story [ 155 ms ] thread
If this was in PHP people would be crying out what a bad and horrible language it is.

Javascript it's seen as an amusing conundrum.

The only reason something like this makes it to the front page, is because of the popularity of things like node.js right now. This is a bug, not a feature.
The crazy part is that it's not a bug; it's behaving exactly as it's specified to.
(comment deleted)
No, no it's not. It's actually part of ECMA-262.

Javascript allows numbers to be a number, NaN or positive/negative infinity. It is well specified within the spec that "Division of a nonzero finite value by a zero results in a signed infinity. The sign is determined by the rule already stated above." [1]

Before you get your knickers in a twist, this is compliant with IEEE 754; although the IEEE define it as an exception.

1. ECMA-262, pg 74, "11.5.2 Applying the / Operator"

I understand that this is part of the spec. But that is a bug to allow division by zero to return a string, and then allow a string to have it's first letter indexed by a math function as a representation of a non base 10 number, is a bug! Just because it is part of the spec doesn't make it a sane addition to the language.
Division by zero doesn't return a string. It returns a well defined value that is within the domain of the data type, which is positive infinity. parseInt does what it is specified to do - it takes the numerical value (positive infinity) and converts it to a string, then searches the string for the first character that it recognises as a contiguous number ("I", which is 18 in base 19). If it finds one, then it returns the value as an integer, if not then it returns NaN.

So not a bug, though I agree the string search is particularly silly. It can't be a bug if it does what the specified algorithm says it does. It would be a bug if it gave a different result.

The reason javascript won't get nearly as much ridicule as PHP is because there's no other choice with javascript. Most arguments against PHP are in the form - I'm using <super awesome language> because PHP has .... faults.

Also, the fact that very few people code pure javascript, instead choosing frameworks like jquery, goes to show how much people like it!

> Also, the fact that very few people code pure javascript, instead choosing frameworks like jquery, goes to show how much people like it!

I'd say most languages are coded in frameworks and not just the "pure" language.

I second this. Javascript is a dumpster-fire of a language, as is PHP. If I could use anything other than javascript for scripting in the browser, I would, but I can't. So I use it. I can use things other than php on the server, so I do.

However, I'd say the use of libraries and frameworks help javascript programmers, for sure, but that doesn't make the language any less of a mess (and in some cases, like jQuery setting "this" to whatever the hell it wants, makes it more of a mess). I can't speak for php, because I've used it far less, but I suspect the same holds true there, too.

I'm unclear what in particular is such a mess about Javascript?
Clearly my comment has annoyed someone. I'm actually quite serious though; rather than voting me down, perhaps an answer (or even just a link!) would be more useful to the discussion at hand.
I have not read the book, but I'm told that (despite being only 176 pages) half of that book actually talks about language flaws and bad parts and only half of the book is actually about the good parts. Again, have not read it, just what I was told.
There is are a couple appendices at the end that discuss the truly terrible and the simply bad-but-work-aroundable parts. Most of it is discusses the subset of the language that is powerful and expressive. He starts the book off by saying "Javascript is a steaming pile of good intentions" which pretty much sets the tone for the rest of the book.

You should read it. It IS very short and can be read in one sitting. Then you wouldn't be left to trust the word of others.

Javascript's maze of type coercion rules produce results which manage to be frequently wrong but in ever more bewildering ways only slightly less crackheaded than PHP. It's also saddled with Java's inexcusable "everything is an object, except for all the crap that isn't" philosophy. http://wtfjs.com/ is a growing list, but a few of my favorites:

  [] != []
  [] == ![]
  {} + [] is 0
  [] + {} is "[object Object]"
  {} + {} is NaN
To be exact, {} + {} is NaN only when used as a statement. In fact it is equivalent to {}; +{} which results in the last statement being evaluated as NaN. When you put parentheses around it (e.g. ({}+{})) it evaluates to "[object Object][object Object]", which should be obvious from [] + {} if it were indeed obvious.
Yeah, the people talking about this are talking about it due to a five-minute lightning talk, and honestly it really bothers me that he is making people think that adding two objects together has that behavior when in fact it has nothing to do with objects at all: it has much more to do with automatic semi-colon insertion than with scary type conversion.
Sorry, your point about jQuery is off the mark. jQuery is a library (not a framework), and if you are not using libraries you are most likely doing it wrong, in any language!

jQuery does nothing to alter the language, so people using it are still coding pure JavaScript. jQuery itself is implemented in pure JavaScript.

----

There does exist variants of JavaScript, such as Paper.js, Protovis and maybe even CoffeScript, but these are not what the majority of JavaScript users use.

I'm not so sure whether jQuery can be considered a framework or not. If you're using jQuery properly ($(document.ready).ready() and so forth) jQuery behaves very much like a framework, with inversion of control and other patterns.

JavaScript in the browser has access to the standard JavaScript and DOM libraries. I really don't think that not using any third-party libraries in any language means "you're doing it wrong". Pure JavaScript/DOM can go a very long way (especially in these days of more standard-compliant browsers), just like pure Objective-C & Cocoa or pure C# & .NET.

Finally, while obviously jQuery does not alter the language, it really changed how people approach problems in JavaScript. Code that uses jQuery looks nothing like code that doesn't use it.

jQuery is big and important and has lots of features that you can use or decide not to use. However, if you decide to implement simple animations yourself in a situation where jQuery would have been a fit, you are likely wasting time and effort.

Using jQuery for this does not mean that you like or dislike the language. That was the point I was trying to refute.

Animations is of course also not the only problem you can solve by using jQuery as a library every now and then.

----

For what it's worth, I don't think jQuery qualifies as a framework in the definition on Wikipedia ( http://en.wikipedia.org/wiki/Software_framework ), but this is besides the point.

The difference between library and framework is quite subtle sometimes and in this case many use it interchangeably. You are correct though, jQuery themselves call it a library.

I don't agree to "does nothing to alter the language" though. It changes the way you manipulate DOM across your codebase. When one says 'library', I assume it's something you make calls to to achieve certain functionality. Like an image library or oauth library.

Also, that jquery is implemented in javascript is not relevant in my opinion. Rails is implemented in ruby. Does that make it not-a-framework?

OK, then we have different understandings of what makes a language.

You said: "the fact that very few people code pure javascript (...) goes to show how much people like it!"

I argue that using jQuery does not change the "pure JavaScript"-ness of any code, just like using Rails does not change the "pure Ruby"-ness of any code, just like using libpng does not change the "pure C"-ness of any code. In every case, it's all in one language anyway -- therefore it is pure in that language.

This comment is not intended to be an argument either way. I am just trying to clarify exactly which point of view I have been trying to argue :)

The reality is that nobody writes parseInt(1/0, 19). Get off your high horse.
it is just an example, but it shows the kind of danger/potential bugs comes with using a badly designed language.

PS : I know it had been designed in 11 days and as such it is an achievement, but as the most used programming language it is quite awful.

Do people really use the "11 days" thing in defense of javascript? I get that it was rushed into production, and all things considered, that was probably the appropriate thing to do given its intended use at the time. But it doesn't matter. I think we have to realize we've collectively failed by not developing an alternative to this tool that clearly wasn't designed for the things modern web applications want/need.
There's nothing "clearly" about it. What in particular can't it do that you want it to do?
I don't even see why this is such a sign of bad design. There are tons of things in JavaScript (and virtually every other language, if not all of them) that are bad design; the fact that parseInt takes a string as its first argument and that 1/0 is the string "Infinity" really doesn't seem like it should qualify.

The fact that we are looking at parseInt as a potential problem here doesn't even make sense, given that the way most developers at this point actually expect functions like parseInt to work is to stop at the first non-number, and the developer in this case specifically went out of their way to choose a radix where I is a number.

Things that could have happened instead:

1) parseInt could fail if it is passed a string that contains anything that is not a digit (this would surprise many developers: again, this is highly common behavior)

2) 1/0 could throw an exception (I would argue this isn't even useful: +Inf is a valuable result)

3) +Inf could return something other than Infinity if converted to a string (maybe the infinity symbol in unicode?)

4) +Inf could refuse to be converted to a string (this is awkward, given that any other number can be converted to a string)

5) numbers could always refuse to be automatically converted to strings (I actually agree with this, but I feel like I'm in the minority: 'a' + 4 + 'b' would therefore also hopefully be illegal; this is an argument for a separate string concatenation operator)

6) parseInt could specifically refuse to automatically convert its argument to a string (this is probably the most reasonable thing that could have been different; however, tons of languages, including ones considered to have amazing type systems like Scala, support implicit conversion and don't even offer this kind of override flexibity)

Which are you claiming is the bad design? Maybe there's something I'm missing? I mean, if this was a situation where 4 + '1a' yielded the result '5' I'd be sufficiently angry as to claim that the people who designed this language were incompetent or dangerously negligant (PHP probably does this... MySQL almost certainly does ;P j/k, btw, only semi-serious), but this behavior seems somewhat reasonable.

One bit I think is poor design is that parseInt parses all characters until it finds a non numeric one. It can introduce some really subtle bugs.
That was my potential complaint/fix #1: that parseInt could refuse to work if it is passed a string that contains things that aren't valid digits in whatever radix it is working in. I personally believe I agree with you, but this is actually the way these functions work in most languages. In particular, this is the behavior of the various functions in C, such as atoi and strtol. While this isn't then "best of breed" behavior, I don't think it is unreasonable behavior. (Python's int() does not do this, for what it is worth: it gets angry and throws an exception if you pass it something that isn't entirely a number.)
(comment deleted)
Python does (5) and it's pretty refreshing. I'm sure other languages with more elaborate type systems do as well, but it's nice to see in an ostensibly "scripty" language.

I think another interesting thing to note is that many languages that do make a distinction (at the type level) between integer types and floating point types (that is, ones like IEEE 754 floats with defined NaN and +/- Infinity behavior) do allow 1f / 0f [1], but raise an error on 1 / 0. Avoiding automatic type coercions (either between ints and floats or between floats and strings) would make it more clear what actually happens in that case.

[1]: Except, apparently, Python! Who knew: http://bytes.com/topic/python/answers/769104-turn-off-zerodi... ?

I strongly disagree on #1. If I hand you something to parse in any context and it isn't valid, I expect you to tell me it wasn't valid (the one big exclusion to this is HTML in the browser).

I weakly disagree on #2. There are cases where +Inf is valuable, but I've never seen it in the browser. That doesn't mean it doesn't exist in the browser, just that I think it is an error far more than it is expected.

I think #3 would need to exist because 1 and 2 are wrong.

I totally agree with #5. That little simplification is the source of endless subtle bugs.

And #6 is an interesting one. I think it is related to #5, though. A language should first and foremost be consistent. If it automatically coerces in some conditions, it probably should in all[1].

1. Said while it is late and I haven't really thought through all the potential ramifications.

The browser is just another programming environment: people are now doing distributed computation and 3D engine development in JavaScript; if you believe that +Inf is valuable anywhere, it should be no different in the browser.

To me the argument against trying to fix #3 is that this is already a type domain error: if you are doing division on any two numbers and expecting to be able to take the result, as if it were a string, and pass that to a function called parseInt (as in, "integer"), you are already doing something fundamentally wrong.

I mean, the semantics of the code in question are just stupid: take two integers (yes, I realize JavaScript has no concept of integers vs. doubles), divide to get a rational number, pass that rational number to a function that takes a string that is supposed to represent an integer, and claim that that string is in base 19...

So, arguably, the real goal here should just be "keep the developer from doing something this stupid", as there really isn't anything more reasonable to have happened: it isn't like it should return 0 (incorrect result) or +Inf (not an integer); it could return null, or thrown an exception, but it should not work: the only question is "why should it not work".

To make it not work in a sensible way, we then need to ask ourselves "what is the underlying mistake here", and I believe that it really has nothing to do with the 1/0: if I somehow managed to accidentally pass 1/2 to parseInt with a radix of 19, I'd also want an exception. Hell, in a more-perfect universe, I'd like to get an exception even if I pass 2/2 to parseInt with a radix of 19.

I can thereby totally feel for the argument that parseInt should throw an exception (maybe return null) if the string does not represent an integer. However, I continue to find it a stretch to claim that that is bad language design... maybe bad library design, but again that is how that function works in most languages.

From a language design perspective, the problem is either 1) that this function (parseInt) made sense to have been written at all, 2) that this block of code using it was allowed to be executed in the first place, or 3) that the developer was led to believe, based on other language constructs, that this was sufficiently reasonable to be typed by a developer.

Looking at it in this light, some languages are even well-enough designed to allow a function with the semantics of parseInt to exist and yet not allow this call at compile time: the fact that we have to wait until runtime to figure out that this code is wrong is then arguably "bad language design" (although, of course, has other interesting tradeoffs that people sometimes prefer).

This notion of "choose the language feature that best disuades this entire class of error" appeal is therefore why, were we to have a time machine to change JavaScript before it got entrenched, I would go with #5 (refusing to cast from a number to a string, and preferably also adding a dedicated string concatenation operator).

The key advantage is that #5 is a language change that fundamentally removes this kind of mistake from everywhere it could occur, while not adding a static type system or otherwise screwing with the set of data types (which would drastically change the overall character and abilities of the rest of the language "JavaScript").

(As an aside: I personally believe that the notion of "string with specific semantics" is something that can and should also be considered when designing type systems, but the ramifications of building something like that are more worthy of a PhD, or at least a Master's, thesis than a tiny post on a web forum. ;P)

What does this example have to do with language design? Eval, for instance, introducing lexical bindings is bad language design. This is mereley an API with a poor contract.
Isn't this a problem with any weakly typed language though? This same problem comes up in Perl and php. When you do type coercion, weird edge cases come up.
Just because you have weak types does not mean you have to have automatic coercion.
That's actually a widely accepted definition of "weak types": automatic type coercion. That said, "weakly typed" is not a well-defined term and I prefer not to use it.

Note that it is not the same as dynamic types. A dynamic type system is a well-defined concept and says nothing about type coercion.

The reality is that flaws like that are seldom skin deep, and can bite you in other parts of the language, even where you don't expect them.

Lack of type safety in a dynamic language is one thing, but awful type coercion is a different beast altogether.

First, Javascript isn't nearly as bad as PHP. Second, even the biggest fans of Javascript recognize its problems (the same can't be said of PHP). Third, even the biggest decractors of Javascript recognize its one overwhelming strength: It's the only language to run in the browser.
Remember that the main reason PHP has such a broad user base is that it runs with fairly comparatively little setup on every server out there. That doesn't make it good. JavaScript is the only language to run in the browser because years ago someone developed it for that purpose. We could be using Python or Ruby or Brainfuck if there were any way to convince all major browser vendors to support that directly.
ISTR that Eich said he originally planned on Scheme in the browser, but for marketing reasons was ordered to make it look more like Java.
I know! In PHP, try the equivalent:

  print intval(NaN, 19);
Result in PHP 5.2.17 is:

  0
Clearly, that is correct.

PHP does the following:

  intval('42', 8); // => 34
  intval(42, 8);   // => 42
Now try:

  print intval(strval("19.99"*100));
  print "<br>";
  print intval("19.99"*100);
This returns:

  1999
  1998
That is not equivalent: 1/0 returns +Inf, not NaN. In JavaScript, parseInt(NaN, 19) actually returns NaN, as there are no valid digits below radix 19 in the string "NaN". PHP, in fact, has the same behavior that JavaScript does: if you do parseInt or intval on (NaN, 24) you will get 13511 (23 * 24 * 24 + 10 * 24 + 23) in either language.

Unrelated, it seems like intval(1/0, 19) in PHP also returns 0 because 1) intval returns 0 if given an empty string (JavaScript's parseInt returns NaN if given an empty string) and 2) 1/0 seems to return something hilarious... it converts to "", but gettype() on it returns "boolean"... I sadly don't know PHP well enough to understand what it is ;P.

(comment deleted)
(comment deleted)
(comment deleted)
Please put Python or Ruby or X in the browser.

Javascript is no better than PHP. It is there - like Php in its time- because we have no other choice.

We're supposed to be professionals and one of our main tool is a joke.

No one is stopping you from rolling your own browser and taking market share away from the current Big Three.

Or from forking Chrome, since it's open source, and then offering your patch back to the central repo. Not sure if Firefox is open source, but could use that instead, too, if it is.

Firefox is not only open source, as it's developed mostly by the community, in cooperation with a non-profit foundation (Mozilla), whose mission is to keep the Internet open and free for everyone to participate.

Chrome is a closed source browser based on the open source Chromium, and it includes some features that the open version doesn't, like embedded PDF reader or MP3 support.

Nobody would use it as it wouldn't have market share. But that's besides the point. The behaviour is actually well defined; the only issue is with parseInt() taking the first character it sees as a number, converting it from it's base to base 10 and then prints the number. The issue being, of course, is that it would have been more sensible to given an exception for non-numeric strings.
> Nobody would use it as it wouldn't have market share.

That's why I added the part about forking and contributing back. If it becomes part of the standard offering, then you don't have to worry about market share as much.

And especially if you get a portable implementation then the IE and Chrome teams might decide to adapt it in, since you've lowered the engineering cost.

> But that's besides the point. The behaviour is actually well defined

There's a good reason to not use Javascript, if there's an option to use another language in the browser, that has nothing to do with JS's quality itself: context switching. Node.js is popular due in no small part to the fact that you have to use JS anyways. The purpose of GWT, as far as I'm aware, is to make it so you have Java as an option in the client.

Python also has plenty of stupid edge cases while being less functional, flexible but more complex than JavaScript. My theory is that Python gets good press because nobody has to use Python, so the people who don't like it just use a different language instead of complaining. Obviously, this does not hold for JavaScript.

If you're going to complain about language choices, don't force everybody on Python!

I can't comment on Ruby because I have never had to use it.

What would be perfect is Scheme in the browser. And, apparently, we almost had it except marketing or management forced Eich to make it look like Java resulting in JavaScript.

Ah! Nice work - that makes total sense.

Incidentally, PHP doesn't have the concept of positive or negative Infinity, just NaN. However, when I tried:

  print inval(1/0);
I got an exception. But point taken :-)

Edit: I might not be correct about positive or negative infinity in PHP... apologies if I have at all mislead anyone!

Also: got a proxy error, so this got reposted, then I deleted one of the posts, but the other post got marked deleted. So third post about this!

Please read my comment below regarding this behavior in PHP. In addition, I will add that 1/0 here is not returning NaN (if you attempt to print it as a string you won't get "NaN"), and intval itself actually has the same behavior as JavaScript. (edit: Oh, I just realized the other comment I replied to was also you. ;P)
Argh! Sorry, proxy error caused all sorts of problems :(
Am I the only one that has laugh maniacally after reading this? X-D
Contrary to what some people may think, this is non-obvious & surprising behavior which has nothing to do with JS being a "dynamic language". It requires knowing that the IEEE floating point standard arbitrarily defines 1/0 as positive infinity instead of being (the more widely accepted, obvious and unsurprising) undefined value. I believe JS is a powerful language but calling this reasonable behavior smacks of Stockholm Syndrome.
It is mainly related to the fact that parseInt in JS slightly converts a positive infinity to a string "Infinity". Base 19 does not add anything to the humor. And well, neither does the presence of a positive infinity itself.

So yes, this is nothing to do with JS being a dynamic language (which main feature is not a variable/slot but a value having a type), but it's something to do with it being a weakly typed language (which main feature is an implicit and generally unpredictable type conversion). Of course many popular dynamic languages are still strongly typed in this sense.

that js implements the floating point standard is not js' fault. but that parse("1something unreasonable", 2) == 1 is just wrong. it should generate an exception.
this wouldn't actually solve the problem for base 36, though.
Actually it would break on the space character.
that's why i included a space character :D.
If the string only had base 36 digits (ie not a space as above), then it wouldn't be a problem, it would a perfectly fine conversion from base36 string to base10 number.
I would say the (bigger) problem is in JavaScript randomly calling toString on things, especially when you're calling parseInt on a number already.
Generally type coercion seems like a bad idea in most languages
Which is why you can use === to bypass type coercion when dong an equality test.
But === is the other equals, not the equals.

Also, that only helps in boolean contexts, not with any function calls.

Also, that only helps in boolean contexts, not with any function calls.

Could you clarify?

'1' === 1 is false, because === is strict.

But there's no strict equivalent of + or -, so '1' + 1 is '11', but '1' - 1 is 0.

The same holds for parseInt('Ambulance', 16) and parseInt('A', 16), which are both 10.