3 ms·
I know this seems weird at first glance, but JS arrays are not typed. To all the people saying this is obviously wrong, I'm curious what your intuitive default
by danShumway 6y ago
I know this seems weird at first glance, but JS arrays are not typed. To all the people saying this is obviously wrong, I'm curious what your intuitive default strategy is to sort the following array:
[
7,
'3',
{},
null,
undefined,
NaN,
Infinity,
new Date(),
new Error(),
Promise.resolve(),
function () { return 'a'; },
{ toString: ()=>'a' },
{ toString: ()=>7 },
{ valueOf: ()=>'b' },
{ valueOf: ()=>9 },
{ __proto__: Number.prototype,
valueOf: ()=>'a',
toString: ()=>7 },
].sort()
The big thing everyone is always complaining about with Javascript is that it tries to guess too much. Type conversions with equality operators, type conversions with +/- operators, lots of Javascript doing unexpected conversions and trying to be helpful at the wrong times.
So sure, you could have a set of random rules based on prototype chains to figure out whether you were going to call `valueOf` or `toString` for any given object, and you could come up with a bunch of rules for whether or not primitive types like Symbols come before numbers.
Or, you could just say, "we're going to convert every value to its string representation and sort alphabetically." At which point, as long as you understand how string conversion works, it becomes very obvious and easy to understand how the array above will get sorted.
The second option is easier to learn and easier to reason about. There's weird stuff in Javascript, but if you're going to have a default (and there's good reason to say that you shouldn't, and that `sort` without a parameter should just throw an error), I think this is the right choice for them to have made about how the default should work.
Lots of intuitions about what the developer meant seem simple when you're only looking at the simple case. But it is usually better to have one set of rules that are easy to describe and that are universally applied. More of Javascript should work this way, if we're going to have a default sorting algorithm, then it's good that the default sorting algorithm mostly does the same stuff every time no matter what you pass it.
This is not the kind of thing that makes me dislike Javascript, it's the other stuff -- the inconsistencies and magic behaviors -- that give me more pause about the language. But what Javascript is doing here is good.
- brundolf 6y agoPython also has untyped arrays, and it: 1) Uses < for whatever types are present 2) Throws an error if two of those types are non-comparable I think that's a much better approach than the implicit casting that happens, frankly, all throughout JavaScript. I like JavaScript - more than Python, overall - but this is one of those things where I don't think we need to be defending the unfortunate decisions that were made in the past.
- danShumway 6y ago> Throws an error if two of those types are non-comparable The problem is that practically everything in Javascript is comparable. This doesn't really solve the sorting conundrum, it just rephrases it. What's the intuitive way to handle: 5 < {} 5 < '10' 5 < 'hat' 5 < function () {} 5 < { toString: ()=>15 } 5 < { toString: ()=>'15' } 5 < { toString: ()=>15, valueOf: ()=>2 } ({}) < ({}) If your assertion is that all of those should just throw errors and we should stop doing type inference entirely, then that's kind of reasonable, I guess, but that's a much more drastic change to how Javascript works. If the assertion is that thinking through Javascript operator conversions is easier than thinking through string conversions, I just disagree with that. Javascript's operator conversions are more complicated and have more weird rules and edge cases. They are (somewhat justifiably) one of the biggest things people complain about in the language. The last thing I want is to have to explain to a new programmer why `5 < '10'`, and `5 > '3'`, but also `'5' > '10'`. Given the way that Javascript is set up at its core, I think using comparison operators for a default sort method would be a disaster. Using `<` as it's implemented today would mean that even a simple array like `[5, '10', '3']` would sort non-deterministically depending on what the sorting algorithm was and what order the indices were compared with each other. It's unusable unless you're going to change how Javascript operators work.
- brundolf 6y ago> The problem is that practically everything in Javascript is comparable > If your assertion is that all of those should just throw errors and we should stop doing type inference entirely, then that's kind of reasonable, I guess The thing is that the above isn't actually type inference, it's type casting. There's a difference. And in JS, implicit casts happen not just in "reasonable" cases like int -> float, but between every possible type: "[object Object]" == {} // true This, to my mind, is JavaScript's greatest remaining flaw in 2020. It's the whole reason the triple-equals (===) operator was added, but that only solves one common case. So my basic argument is: in totally unreasonable implicit-casting scenarios (which is most of them), it's much better for a language to err than to make a "best effort" guess at casting the values to be the same type. All of that said: JavaScript is the way it is, and unlike lots of other things that have been papered-over with new features over the years, this issue is so foundational that I don't think it can ever be fixed outside of just learning to avoid the places where it shows up.
- naikrovek 6y ago> I'm curious what your intuitive default strategy is to sort the following array It doesn't make sense to sort an array containing different types at all so why is this even allowed at all? JavaScript will forever be a very successful toy because of things like this. Types are important, and the tweet begins to expose why.
- danShumway 6y ago> JavaScript will forever be a very successful toy because of things like this. Types are important, and the tweet begins to expose why. The "everything should be strongly typed" argument is not one that I'm necessarily unsympathetic to, but I also just don't feel like it's relevant here. Javascript isn't strongly typed. What did you expect the spec authors to do, break the entire web just so that they could have a better `sort` method? They built a decent algorithm given the language and paradigms that they were building on. Soon everyone who hates Javascript will be able to use Rust/C/C# targetting WASM, and hopefully these pointless "it's a toy language" debates will calm down once that option goes more mainstream.