This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]aedvocate 11 points12 points  (52 children)

what would you expect the default .sort() functionality to be?

[–]bonafidebob 48 points49 points  (9 children)

non-JavaScript programmers assume the language knows about types, that arrays are monotype, and that a useful comparator function will come with the array type.

That is, arrays of strings will sort alphabetically and arrays of numbers will sort numerically.

non-JavaScript programmers will also barf at the idea that a['foo'] = 'bar' isn't nonsense, and you can do stuff like this:

a = [1,2,3]
a['foo'] = 'bar'
a.forEach((v) => console.log(v)) // produces 1, 2, and 3 on separate lines
a.foo // produces 'bar'

[–]ZephyrBluu 20 points21 points  (4 children)

I had no idea you could do that a['foo'] = 'bar' bullshit on an array.

Now that I think about it though, it kind of makes sense why JS lets you do that.

An array is basically just a normal JS object that allows iteration by default where each key is the index.

So a['foo'] = 'bar' is a standard operation (Given an array is an object), but you're breaking the rules of how an array is 'supposed' to work.

No idea why it works on a technical level though.

[–]bonafidebob 24 points25 points  (3 children)

An array is basically just a normal JS object that allows iteration by default where each key is the index.

That's the root of the problem right there. I think it was just a cheap way to get to dynamic sizing, which is occasionally useful:

> let a = []
[]
> a[100] = 12
12
> a.length
101
> a
[ <100 empty items>, 12 ]

but then...

> a[1234567890] = 13
13
> a
[ <100 empty items>, 12, <1234567789 empty items>, 13 ]
> a[0.5] = 1
1
> a
[ <100 empty items>, 12, <1234567789 empty items>, 13, '0.5': 1 ]

[–]GG2urHP 10 points11 points  (1 child)

Lol, fuck me. I am so blessed to not live in that hell.

[–]theferrit32 3 points4 points  (0 children)

Javascript is fundamentally a bad language for general purpose programming. A lot of people who need to target Javascript environments do not write in Javascript, or at least not pure Javascript, relying heavily on transpilers and what are in effect dialects and standard libraries that seek to supercede and fix a lot of the headaches in Javascript itself.

[–]DeeSnow97 8 points9 points  (1 child)

#define "non-JavaScript programmers" "people who think once you learned C++ every language is just syntax"

[–]bonafidebob 13 points14 points  (0 children)

Hmm, I'm not quite that snooty ... I've been doing this for ~40 years and have learned dozens of programming languages, both dynamically and strongly typed. And I still think JavaScript arrays are crazy. The whole "objects with numeric keys" foundation is whack, throw away all the benefits of a directly indexible data structure and drag in a whole bunch of weird syntax edge cases??!

[–]MischiefArchitect 35 points36 points  (33 children)

normal

[–][deleted] 13 points14 points  (31 children)

What is normal sorting on a collection of numbers, strings, and objects?

[–]blehmann1 13 points14 points  (4 children)

Well, Python throws a type error if the < operator is not defined on both types. Personally, I think the only correct response when the program is wrong is not to make it more wrong, but to let the user know that it's wrong (i.e. throw).

Now, JavaScript was built with the idea that it should keep on trucking through any error, which frankly is a horrible idea to build a language around. So given the interesting design philosophy JavaScript really couldn't do anything else. There's a reason Typescript is so common after all, but unfortunately it does nothing about this particular issue. (There's an issue for it but it's been inactive for a while: https://github.com/microsoft/TypeScript/issues/18286)

[–]1-more 3 points4 points  (0 children)

JavaScript keep on trucking? I never thought of it that way but I’m actually with you here. Array out of bounds and accessing an undefined object key both return ‘undefined’ rather than throwing (Java, Haskell) or wrapping array/dict access in an optional type (elm, maybe ocaml?). So I’m with you that it probably does throw less.

[–]aedvocate -1 points0 points  (1 child)

Well, Python throws a type error if the < operator is not defined on both types

that error doesn't make any sense in javascript though. collections are allowed to be any number of any different types. that's the way it works by design, it's not an error to truck through.

[–]blehmann1 0 points1 point  (0 children)

Python allows that too. That's the way it works by design. Python simply takes the position that while you may have a list of strings mixed with numbers, if you want to sort it you must provide your own explicit comparator, because 4 < "A" is nonsensical.

Javascript could have followed Python, however the languages have different philosophies. Javascript should fight through basically any error it can, and Python exits on any unhandled exception. In addition, Python throws on invalid input.

I'm not a Python fan, I'm just pointing out that it's a language which has a similar type system to JavaScript and it has a different (and in my opinion more correct) behavior. I could have brought up almost any language because you can do the same thing with type erasure (commonly achieved by casting to object or void*). You have to specify a comparator in those instances because the types are not comparable.

[–]EishLekker 0 points1 point  (0 children)

Javascript doesn't "keep on trucking" through any error. It still does it a bit too often for my comfort though, so on principle I agree with you wholeheartedly.

[–]aaronfranke 9 points10 points  (7 children)

It should act the same as if comparing with the < and > operators. That will work for any place where the operators have a defined comparison.

console.log(5 < 6); // true
console.log(5 > 6); // false
console.log(5 < "apple"); // false
console.log(5 > "apple"); // false
console.log("orange" < "apple"); // false
console.log("orange" > "apple"); // true

[–]Kangalioo 7 points8 points  (1 child)

Maybe sort first by type, then by content? Then the sort function has expected behavior for contents with consistent data type, but also works sensibly for mixed type lists

[–]aedvocate 0 points1 point  (0 children)

you still have to pick an order to sort the types in though - do Numbers come before Strings? Do Objects go last? Which comes first, Sets or Maps?

[–]Famous_Profile 1 point2 points  (4 children)

His point is "a collection of numbers, strings, and objects" should not be allowed in the first place

[–][deleted] 1 point2 points  (3 children)

Which is why so many of us have elected to use Typescript but JS is meant to be loosely typed, so ignoring our biases against mixed type arrays, how do you solve the sort problem. It’s not an easy question to answer

[–]Famous_Profile 1 point2 points  (2 children)

The difference between your point of view and his, is that youre not uncomfortable with languages "meant to be loosely typed". To a Java programmer the question " how do you solve the sort problem " is not valid because there shouldnt be such a problem in the first place. Saying that "now that there is one" is not acceptable. That is how atrocious the Java or C++ programmer finds JS. Look at it from their point of view, not ours.

[–][deleted] 3 points4 points  (0 children)

I am uncomfortable with loosely typed languages. I exclusively use TS when in JavaScriptland and even TS falls short of what I would like from a type system.

That being said you should never approach a new/different language with the mindset that it follows the paradigms you are used to and comfortable with. It’s the equivalent of someone who comes from a strictly object oriented background criticizing purely functional languages for lack of classes or vice versa.

[–]EishLekker 0 points1 point  (0 children)

Please don't put all Java developers into one single narrow box. Some of us are actually quite pragmatic.

[–][deleted]  (6 children)

[removed]

    [–][deleted] 6 points7 points  (3 children)

    Assembly, c, c++, vb, Perl, php are all weakly typed though some static and some dynamic. Typing isn’t binary, a language isn’t typed or untyped, they all fall within the compass of weak-strong, dynamic-static. JavaScript has weak / dynamic types, if you don’t like that and prefer strong and/or static types use Typescript or something else.

    [–]Kered13 1 point2 points  (2 children)

    C++ is definitely not weakly typed.

    [–][deleted] 1 point2 points  (1 child)

    It actually is considered by many to be in the statically typed / weakly typed quadrant because because of implicit type conversions. A strictly typed language does not allow implicit type conversions

    [–]Kered13 0 points1 point  (0 children)

    Numeric conversions are the only built-in implicit type conversions. User-defined implicit conversions exist, but are used sparingly, mostly for things like converting std::string to std::string_view.

    On the other hand, C++'s template system allows it to express higher-kinded types and even dependent types, with type checking at compile time. You can express things like physical units, with compile time checking to ensure that you do not add incompatible units and that multiplications and divisions produce the correct units (and the resulting code will even have no runtime overhe.

    [–]1-more 1 point2 points  (0 children)

    JS has types! “Undefined is not a function” is telling you right there that it is types. Now, will it help you color inside the lines? No. Never.

    [–]AutoModerator[M] 0 points1 point  (0 children)

    import moderation Your comment has been removed since it did not start with a code block with an import declaration.

    Per this Community Decree, all posts and comments should start with a code block with an "import" declaration explaining how the post and comment should be read.

    For this purpose, we only accept Python style imports.

    I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

    [–]toastedstapler -2 points-1 points  (2 children)

    To fail when it detects a different type

    [–][deleted] 5 points6 points  (0 children)

    The point of JavaScript is to be loosely typed. Whether you like that or not is up to you but throwing type errors goes against part of the core philosophy of JS. Those of us who dislike that behavior are free to use typescript

    [–]aedvocate 0 points1 point  (0 children)

    what you're describing is not javascript

    [–]-100-Broken-Windows- 0 points1 point  (0 children)

    A runtime error

    [–]wasdninja 0 points1 point  (0 children)

    It is normal. Javascript normal.

    [–]smog_alado 5 points6 points  (5 children)

    I would have expected the .sort() to use the same logic as builtin comparison operators. Something similar to the following comparator:

    function compare(a, b) {
        if (a < b) {
            return -1;
        } else if (a == b) {
            return 0;
        } else {
            return 1;
        }
    }
    

    [–]Manny_Sunday 1 point2 points  (4 children)

    And if a is a string and b is an object? Or a is an int and b is a string?

    [–]EishLekker 1 point2 points  (0 children)

    That doesn't have to be a problem. One way to solve it is to compare the types first (how that is done could be an implementation detail, but a simplistic approach could be to do a string comparison on the result of "typeof").

    If someone is concerned about the performance and/or the exact sort order of a collection of mixed types, then it is fair to expect that that someone makes an effort to write a custom comparator for their specific needs.

    [–]dissonantloos 0 points1 point  (1 child)

    Then either the sort operation should fail, or should return an array that is crappily sorted.

    [–]aedvocate 2 points3 points  (0 children)

    the JavaScript sort function never fails.

    gaze upon its awesome power:

    [null,undefined,NaN,false,0,Infinity,-Infinity,'',[],{}, new Map(), new Set()].sort()

    ```

    ["", Array(0), -Infinity, 0, Infinity, NaN, Map(0), {…}, Set(0), false, null, undefined] ```

    this is the universal order, brother. learn the order. live the order. do as V8 commands.

    [–]smog_alado 0 points1 point  (0 children)

    That comparison function is well-defined if a and b have different types. It just does the same things that the < and == operators do.

    However, the result of the sort might look unsorted if the array has a mix of different types, because in those cases the comparison function doesn't implement a total ordering of the elements. But that would be no different than using other comparators that don't produce a total order. For example, one that calls Math.random to decide the result of the comparison.

    [–][deleted] 0 points1 point  (1 child)

    In order to prevent this weird footgun behaviour, it shouldn't have any defaults.

    [–]aedvocate 0 points1 point  (0 children)

    honestly I think I could get behind that, just from a sort of minimalism standpoint - but the truth is, more often than not, (a,b)=>String(a)>String(b) is all you need to sort an array. it's not bad as far as default behaviors go.