Live data from Hacker News

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

medium.com

101–110 of 163 posts

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

#102
post #97

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…

> - The language design allows your brain to ignore the index parameter because JS accepts superfluous parameters, which is a terrible decision. Without that we would not be able to have variable length argument lists in the past.

Yes, but again that's the consequence of another bad design: not including spread or another metaprogramming system for this. And not having default values either.

Spread has existed in Python forever under the name of "splat operator", default values as well. Same with ruby.

That what I meant when I said "they accumulate". A bad design decision not only affect the user cognitive load and productivity, but it also cascades to the rest of the language and shapes it.

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

#103
post #51

Earlier quoted context omitted.

There's some interesting history for awareness of the first issue: parseInt used to be a notorious source of bugs and so it used to be more common to see it with a second argument on any project which used a linter in that era. ES5 deprecated that behaviour and it's been widespread enough that code which started in the IE9+ era now looks like the very old buggy code omitting the radix, so anyone getting started relat…

I didn't know about the second parameter until I saw it in a TypeScript signature a few months ago, which acted as a sort of warning to me to avoid using it incorrectly. But TypeScript doesn't catch this specific bug because it's technically correct [1] from an API stand-point, as the second parameter to parseInt is a number and the second argument to map's callback is a number. For as many situations as TypeScript g…

Yeah, the problem this one time isn't typing but the JS developers implementing map wrong. Map should not take two arguments. There should be a different function like enumerate in in python for this.

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

#104
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.

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…

> I know all that, have been programming for 15 years, yet I still would have done the mistake.

I have not done it with parseInt per se, but I have made this precise mistake at least twice with passing a function `f` with an optional second argument in `some_array.map(f)`, and it took a while to figure out what was happening each time.

Now that Javascript has proper iterables and iterators and generators, I have been enjoying using versions of `map` and `spreadmap` which take in a callback function and iterables and produce an iterator. Then I can explicitly use `enumerate` if I want it. https://observablehq.com/@jrus/itertools#map

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

#105
The extra args passed by map coupled with the optional extra args in standard methods is the cause of a lot of confusion, but this feels like a missed opportunity for demonstrating functional programming. In the end author suggests

    ['1', '7', '11'].map(numStr => parseInt(numStr));
I think you'd learn something much more useful with

    function radixParser(radix) { return numStr => parseInt(numStr, radix); }
    ['1', '7', '11'].map(radixParser());
    > [ 1, 7, 11 ]
    ['1', '7', '11'].map(radixParser(8));
    > [ 1, 7, 9 ]
    ['1', '7', '11'].map(radixParser(2));
    > [ 1, NaN, 3 ]

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

#106

Earlier quoted context omitted.

0 is a special case where the parser tries to guess based on how the number is formatted. 1 just doesn't make sense at all. Using 0 is the source of many interesting bugs, like when someone puts in an IP address like so: 192.168.010.001 and the client tells you it can't connect (to 192.168.8.1).

As of ES5 010 must be parsed as 8 if you pass in a radix of 0.

Because leading 0 implies octal (Base-8). Interestingly, this is also the standard interpretation of IPv4 addresses in that form, where each delimited number [octet] in an IP address that start with a leading 0 should be read as octal.

(That behavior contrasts interestingly with IPv6 where the numbers [segments] are only supposed to ever be hexadecimal (Base-16) and leading zeroes are to be ignored.)

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

#107

The extra args passed by map coupled with the optional extra args in standard methods is the cause of a lot of confusion, but this feels like a missed opportunity for demonstrating functional programming. In the end author suggests ['1', '7', '11'].map(numStr => parseInt(numStr)); I think you'd learn something much more useful with function radixParser(radix) { return numStr => parseInt(numStr, radix); } ['1', '7', '…

If you're gonna use arrow functions, why not go all the way!

  const radixParser = (radix) => (numStr) => parseInt(numStr, radis);

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

#108
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.

Map ever calling anything with 3 arguments is absolutely strange and surprising and should be borderline offensive to most anyone familiar with the operation from ANY other language.

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

#109
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.

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?
Post reply on HN