Live data from Hacker News

Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

medium.com

111–120 of 163 posts

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#111

Earlier quoted context omitted.

I've developed applications in JS, but don't have extensive experience with it, and I couldn't spot the problem. Frankly, I think if `['1', '2'].map(parseInt)` is both valid and does not result in a collection containing the integers 1 and 2 in that order, that indicates a catastrophic failure of design at some level. These things happen, but usually you have to dig down to a less bog standard example to find it. The…

The problem is that this article is attributing this problem to JS, whereas the problem is with either computer science or human decimal bias: i.e. the radix is not a concept invented by JS. If you think it should be ok for all devs to believe that parseInt === parseDecimalInt then maybe all languages should be decimal-only. That isn't the case though.

[deleted]

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#112

Earlier quoted context omitted.

Yeah, I’m not surprised at all by this. I get that there are a lot of weird things in JS but I don’t think this is a JS oddity. Surprise! You need to know the basics of how your language works.

That's apologist talk pure and simple. The language, silently, does something that's almost certainly wrong. The language has enough information to provide you with a helpful warning or error message that you probably don't want to do this, but instead, it violates the principle of least surprise by just doing the wrong thing instead. The correct error is something along the lines of: let numbers = input.iter().map(p…

If Rust had ergonomic support to pass multiple arguments to a functions you would still not be protected from this bug. Even the type system wouldn't help you there because the index would be of type usize and so would be the radix argument in parseInt (although in reality this would probably be an enum or u8). But this is caused by the interaction of two bad APIs. Even if we have the restriction that it confirms to the over two decades old signature, map should only yield each element of the input and yield back the result of the closure. If you need the index you could chain a call to enumerate before the map and get tuples of value and index. This is what you'd have to do in Rust and Python, for example.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#113
post #4

This isn't strange or surprising. parseInt takes two arguments, the second one is the radix and map will call with three arguments, the value, the index and the whole array. You just have to know this and it might be different in other languages. [ ... ].map(x => ...) is the right way to do this.

> This isn't strange or surprising.

> You just have to know this

Hidden, silent, unintuitive behavior that you "just have to know" (and remember each time you might read or write the code) is absolutely strange and surprising in an engineering context. Javascript's deadly combination of unnecessary unintuitiveness (map's ludicrous API) and permissibility (ignoring extra arguments) strikes again.

The permissibility of guessing what malformed code means is actually somewhat defensible in Javascript's case, since the incentive ecosystem of the Web is complex and frontend parsing has long had a tradition of best-effort parsing instead of throwing an exception. But the absurd signature of map here is half the problem, and there's really no good explanation for that than yet another instance of "Javascript is a dumpster fire that should only be used when forced to". Similarly "easy-to-use" languages like Python can afford strong typing and rejecting extra args when not specified because they're not bound by the Web's permissibility. But Python also, for all its flaws, has adults making language decisions and does the sane thing with APIs like map without loss of expressiveness. Adding loop metadata like indices requires an explicit call to enumerate(), trading off an iota of verbosity for intuitiveness, which is one of the most important things in writing code that can remain productive and bug-free.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#116
post #109

Earlier quoted context omitted.

It may be logical but: - I know all that, have been programming for 15 years, yet I still would have done the mistake. - Simple unit tests may very well not catch this bug the first time. - The language design allows your brain to ignore the index parameter because JS accepts superfluous parameters, which is a terrible decision. - map() is a mapping primitive. It's supposed to adapt a type to another type so that you…

As a (mostly) outsider, I’ve never understood why JavaScript is so popular in web dev circles. There are so many awesome compile-to-JS languages these days (ClojureScript, PureScript, Elm, ReasonML, Scala.js, etc). What makes people want to use JavaScript instead?

Any time you use anything non-native, you add layers of indirection and potentially lots of impedance mismatch between languages/runtimes. For instance, I know all of the ones you mentioned would be non-starters at my current job because it means we would have to wrap all of our JS libraries/APIs in the language of choice, which is a non-trivial amount of work. Plus, debugging becomes more challenging as you're basically having to do it at two levels simultaneously.

Even with all of JavaScript's deficiencies, it's still far easier to just deal with them than to switch languages entirely.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#117
post #109

Earlier quoted context omitted.

It may be logical but: - I know all that, have been programming for 15 years, yet I still would have done the mistake. - Simple unit tests may very well not catch this bug the first time. - The language design allows your brain to ignore the index parameter because JS accepts superfluous parameters, which is a terrible decision. - map() is a mapping primitive. It's supposed to adapt a type to another type so that you…

As a (mostly) outsider, I’ve never understood why JavaScript is so popular in web dev circles. There are so many awesome compile-to-JS languages these days (ClojureScript, PureScript, Elm, ReasonML, Scala.js, etc). What makes people want to use JavaScript instead?

It's permissiveness means you can hit the ground running more easily writing shitty but functional code, and web dev has long been the gateway for new entrants to engineering. People start programming, learn shitty habits from a shitty language ,and then the religious affinity for programming languages that many have starts to kick in.

This obviously doesn't explain every Javascript fan, but the tendency is strong enough to shift the dynamics of the community.

I can't say I relate to the religious fervor with which people defend programming languages. C++ is probably my favorite language to work in, but I absolutely understand where the hatred for it comes from. I readily admit that it's grotesque in many ways and my preference is likely for lack of sustained exposure to certain other modern languages.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#118

Earlier quoted context omitted.

> in most cases there is no need for the average developer to know it This may come off as arrogant but.. I'll proceed nonetheless. There is a need for the average developer to know the interfaces of the functions they're choosing to use. They're well documented, and the documentation is neither hard to find, nor difficult to read. There may be an argument here for strongly typed languages -vs- weakly typed ones, whe…

I don't understand why this is downvoted to death without any replies. Sounds like a reasonable opinion but I'd also love to hear why people think it's downvote-worthy.

Not a downvoter, but I'll have a go:

You might be a dev who isn't very familiar with Javascript, but you still need to fix it. Or you might be having an off day. Or you're writing a critical fix under a lot of pressure and simply forget about the issue. And I'll bet if this code was being reviewed, most devs would still overlook the issue.

There are many real world scenarios where it isn't so easy or clear cut. We're all human, and we make mistakes. In other fields, we try and reduce how easy it is to make these mistakes. Some things will always be dangerous like table saws. But a programming language?

Anyway, the "deal with it"/"get good" mentality just seems like a lack of empathy. Not to mention the arrogant in-group thing of "oh, you don't know of my favourite but flawed language? you must not be a good dev". And the fact that fixing something like this could cumulatively save a huge amount of brainpower for current and future devs.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#119

Earlier quoted context omitted.

The surprising bit comes in with the fact that: 1. parseInt is used with only a single argument in most cases. 2. Only the first argument of map is used in most cases. Using multiple parameters for those are so uncommon that it's easy not to realise that it's supported. _If you know all of that_ it may not be surprising to you, but in most cases there is no need for the average developer to know it, making it very su…

> in most cases there is no need for the average developer to know it This may come off as arrogant but.. I'll proceed nonetheless. There is a need for the average developer to know the interfaces of the functions they're choosing to use. They're well documented, and the documentation is neither hard to find, nor difficult to read. There may be an argument here for strongly typed languages -vs- weakly typed ones, whe…

Instead of thinking about code writing, think about code reading. Every organization has people who wrote buggy code, for a million reasons: they were distracted, they were hurried, they simply aren't that good (at either engineering or the language). Sometimes this stuff gets through review too, particularly in situations with deadlines.

But one of the safeguards here is that clean, intuitive code makes it possible for any engineer who's a little more thoughtful to catch little bugs like this. God knows I've done it dozens of times over the course of my career: while reading code for some other purpose, a block catches my eye as having something off about it, and I dig in and find a bug.

The problem with unintuitiveness,especially when it's baked into the language, is that you don't scrutinize every line of code you encounter with your full brain and attention. Without going on the hunt for "map and Javascript in general are horribly designed, parseInt has a rarely-used second param, root out likely bad uses", my brain on another task would skim right over a map-parseInt call like the above. It reads as if it's correct, and in any sane language it would be.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#120

Earlier quoted context omitted.

Well there's your first problem haha.

Right! It should have a map, map2, map3 function

Nah, there's better solutions; you can create a window/stride method that converts a sequence into a sequence of sequences and then passes that into a map function that takes a single argument.

  array.stride(2).map(|(x,y) ...|)
Both error checking and ergonomics are preserved.
Post reply on HN