If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Enjoy an ad free experience by logging in. Not a member yet? Register.

All we do is pass a decision function. What sort algorithm is actually implemented is up to the Javascript engine. And some do compare elements to themselves -- which will always be a case where you need to return zero. Even in a list of unique elements each element equals at least itself (it's a reflexive relation).

A more pragmatic reason: The specification wants us to cover this case, so we should cover it. If we don't know implementation specifics, we should do what the specification wants us to do -- and the specification says: cover the case of equality.

Using "return a-b" in the case of numeric comparison, as I said, is sufficient of course as it does cover the "return 0" case.

All we do is pass a decision function. What sort algorithm is actually implemented is up to the Javascript engine. And some do compare elements to themselves -- which will always be a case where you need to return zero. Even in a list of unique elements each element equals at least itself (it's a reflexive relation).

i'd have to see it to believe it. some do? which engines? i've traced the sort routine in different browsers before. can you post a sample of the kind of code that produces a different result by omitting zero when sorting a unique string array?

Create, Share, and Debug HTML pages and snippets with a cool new web app I helped create: pagedemos.com

I didn't mean some engines do that, I meant that some algorithms do that – but that's exactly the point: We are JavaScript developers, not browser builders. We don't know what algorithm the browsers (of which there are several) implement and frankly we shouldn't care, plus it is subject to change over time without us noticing. The whole point to a standard like ECMAScript is to have a set of specifications that tells us how to use the interface the browsers' JS engines offer us.

And ECMAScript tells us to return 0 if elements are equal. It doesn't say anything about exceptions to that rule. Therefore the only way to be safe now and in the future is to follow these rules.

Here's an example showing a difference. Consider this array and utility function (tested in Chrome):

The order is not the same but as you can check, both sort functions return a positive number for a.value > b.value. There's a number of ways to make them work the same, but the point is: The two decision functions discussed do not behave the same. The method that is able to return 0 is clearly the better one as it does not switch the elements that we think of as equal.

Here's an example showing a difference. Consider this array and utility function (tested in Chrome):

----------

The order is not the same but as you can check, both sort functions return a positive number for a.value > b.value. There's a number of ways to make them work the same, but the point is: The two decision functions discussed do not behave the same. The method that is able to return 0 is clearly the better one as it does not switch the elements that we think of as equal.

ok, but i explicitly said, twice, that there is no diff when sorting an array of unique strings, like you might get from Object.keys(ob). you posted code sorting an array of objects...

why do people who know the least usually know it the loudest?

a good faith effort, but not the scientific falsification of my hypothesis that we were all hoping for. If i said "all cars are red", and you wheel in a blue motorcycle, that doesn't really change the truthfulness of my statement... FULL DISCLOSURE: i don't expect that you will find a working example that contradicts my assertions about sorting unique Arrays. Maybe you can, it's a crazy world, but i would be pleasantly surprised.

afaik, the only way for a manual sort function to return zero is when the elements are the same. If you have an array of unique strings, that cannot happen. Therefore, that "return 0" branch is orphaned code in the context described.

of course, it's never to late to prove me wrong, i just wouldn't hold my breath on this one.

Last edited by rnd me; 03-01-2013 at 05:33 PM.

Create, Share, and Debug HTML pages and snippets with a cool new web app I helped create: pagedemos.com

ok, but i explicitly said, twice, that there is no diff when sorting an array of unique strings, like you might get from Object.keys(ob). you posted code sorting an array of objects...

I don't think you're getting my point. It is not up to us to decide whether or not we can violate the interface we have been given. We don't know implementation details and they are subject to change, so we should always conform to the standard we are working with. A standard that explicitly states: Return zero on equal elements. It does not state "but omit this if you know you're working on unique elements" anywhere.

It doesn't matter whether or not there is an example that currently works and shows a failing scenario. The off-chance of this being true (which you show to think of as possible by your ever so little fear/hope of there being a counter-example, even if it's because you say "it's a crazy world") and the chance of browser implementations changing (which would be perfectly acceptable if it doesn't break the ECMAScript standard) is reason enough to not omit the case where you return zero.

You're very loudly trying to not understand the fact that this is simply false:

afaik, the only way for a manual sort function to return zero is when the elements are the same. If you have an array of unique strings, that cannot happen.

Your elements may all be different from each other, but if I compare an element to itself, the two elements in question are equal. And some sorting algorithms do compare elements with themselves – are they implemented in any browser? I don't know, I don't care and it doesn't matter.
In fact, even some implementations of Quicksort show this very behavior and Quicksort, unlike the inefficient Bubblesort (which by the way would not do this), is a widely used sorting algorithm, as you surely know.

Edit: This isn't exactly scientific, but sure more proof than you brought up so far: Link.

I know i'm not getting your point. You are raising a warning flag, telling us to look out for a problem, but you can't/won't demonstrate a single instance in which the alleged problem presents itself. You say i don't "understand the fact that this is simply false", but i don't get why, if it's false, you cannot demonstrate it.
Normally when these type of discrepancies surface, we try to work together to isolate the problem and perform diagnostics like "what versions of IE are affected?", "did this stop working in ecma5?", "is there a test?", "is there a polyfill?", etc. I would like figure out how big of a problem this is (if at all) and arrive at a consensus.

We can disagree with opinion like "should i always use strict mode?", but intelligent people cannot/musn't continue to disagree on mechanical realities.

I will concede that i forgot to mention that the string array elements must be unique when COMPARED, not just to each other in the literal sense.
In other words, ["a,"b",A"].sort(function(a,b,c){c="toUppedCase"; return a[c]()>b[c]()?a:-1;}) in not comparability unique.

While a browser can choose to implement some portions of [].sort however they want, the results of their method must conform to the higher-level specified output.

Think of it like parseInt(); you can arrive at an integer through a variety of methods like casting to string and discarding the decimal then calling toNumber, via a bit-shift operation, or by using complimentary mathematics. Regardless of the manner it's implemented, the results are ALWAYS the same, just like they are for the SortCompare internal result handling, or any specific procedure for that matter.

Also consider that it might not actually matter if you are correct in your postulate.
let's assume you are right, and that sometimes a unique value is compared to itself.
Instead of zero, it returns, say, 1. So, it moves below itself in the list.

if i have a list, [a,b,c], and i pluck out b and put it after the spot where b was, my array is still [a,b,c].

Also, when you compare things other than strings, you can easily have two different elements that compare the same.
This is always the case for an array of objects. Also note that sorting upon a property defined using Object.defineProperty() instead of assignment could result in accidental comparability equivalence.

Checking the spec, we see that it's possible to satisfy the criteria outlined while omitting the zero case, depending upon the input set of elements:

15.4.4.11 Array.prototype.sort (comparefn)
The elements of this array are sorted. The sort is not necessarily stable (that is, elements that compare equal
do not necessarily remain in their original order). If comparefn is not undefined, it should be a function that
accepts two arguments x and y and returns a negative value if x < y, zero if x = y, or a positive value if x > y.

wait, doesn't that say it has to return zero? No, it actually does not, it says it must return zero if x=y, which on a unique array, is impossible.
Therefore, it's possible to code a function that when used on a unique array, never encounters the 0 return, and therefore produces the exact same output as one that emitted 0 in the condition that never occurs for the set in question. It also notes that even if you DO return 0, comparability equivalent elements might be re-ordered.

to see [].sort() in action, we can can simply trace the actual procedure with an array of unique strings using the steps below. If xString !=yString, then it's impossible to get to step #18 according to the spec:

When the SortCompare abstract operation is called with two arguments j and k, the following steps are taken:
1. Let jString be ToString(j).
2. Let kString be ToString(k).
3. Let hasj be the result of calling the [[HasProperty]] internal method of obj with argument jString.
4. Let hask be the result of calling the [[HasProperty]] internal method of obj with argument kString.
5. If hasj and hask are both false, then return +0.
6. If hasj is false, then return 1.
7. If hask is false, then return –1.
8. Let x be the result of calling the [[Get]] internal method of obj with argument jString.
9. Let y be the result of calling the [[Get]] internal method of obj with argument kString.
10. If x and y are both undefined, return +0.
11. If x is undefined, return 1.
12. If y is undefined, return 1.
13. If the argument comparefn is not undefined, then
a. If IsCallable(comparefn) is false, throw a TypeError exception.
b. Return the result of calling the [[Call]] internal method of comparefn passing undefined as the this
value and with arguments x and y.
14. Let xString be ToString(x).
15. Let yString be ToString(y).
16. If xString < yString, return -1.
17. If xString > yString, return 1.
18. Return +0.

PS: when i said it's a crazy world, i was talking about IE6 and stuff...

Create, Share, and Debug HTML pages and snippets with a cool new web app I helped create: pagedemos.com

Because luckily, most browsers currently don't show this behavior. But as I have said several times now, there are a lot of browsers and their implementation is subject to change without us noticing it at all.

While a browser can choose to implement some portions of [].sort however they want, the results of their method must conform to the higher-level specified output.

And if their implementation crashes as soon as the function can't ever return 0 in case of equal elements, their implementation would still be conform to the ECMAScript specification.

Think of it like parseInt(); [...]

That's not a good example because it doesn't include the specification dilemma. A better example would be having, say, a function called myFloor whose specification says that it rounds any non-negative real number to the biggest integer that is not bigger than the number. Now, you might be able to use it on negative numbers and, say, get myFloor(-0.2) = 0, which might be what you want. But if implementation changed and would suddenly result in myFloor(-0.2) = -1, then it would be your fault because you have misused the function whose specification only told us what happens on non-negative numbers.

let's assume you are right, and that sometimes a unique value is compared to itself.

This isn't an assumption, it is the truth. I have proven it by providing an explanation and a link with corresponding further explanations. You just gotta not misunderstand me: I'm not saying that every javascript engine in every browser will always compare an element to itself, I'm just saying that there are sort algorithms that do that and that there is no reason why an implementation shouldn't do that and that the ECMAScript standard says nothing about this not happening.

Instead of zero, it returns, say, 1. So, it moves below itself in the list.
if i have a list, [a,b,c], and i pluck out b and put it after the spot where b was, my array is still [a,b,c].

"True", but if you read the link I provided, you would've seen that ignoring the zero case can cause a sort algorithm to crash. No matter what you expect the output to be, if the algorithm simply requires a zero case, then it does. Why would ECMAScript even mention the zero case if it was generally irrelevant? They have their reasons and we don't need to care about them, we just have to write our code conform to it.

Checking the spec, we see that it's possible to satisfy the criteria outlined while omitting the zero case, depending upon the input set of elements:

It does not say that. It's how you interpret it by assuming that elements won't get compared to themselves. Which, once again, I have proven to be false in the general sense.

wait, doesn't that say it has to return zero? No, it actually does not, it says it must return zero if x=y, which on a unique array, is impossible.

And once more: Yes, it is possible in the case of an element being compared to itself. I'm just gonna repeat this a few times because I have said it multiple times before and you seem to try to ignore it. Once more, read the link I provided.

These are really gonna be the last times I will say that some sort algorithms and some sort algorithm implementations do compare elements with themselves. Some of them even can't function properly if you don't cover this case. It's all there for you to read, the specification is clear that you need to return 0 in case of equal elements and since algorithms might compare an element to itself, but we don't know the implementation, the only way to be safe is to include the zero case. If you're still going to ignore these facts that you can openly read up on, there really isn't any point in continuing this discussion. You wanted proof, I have provided proof.

Just to make one thing clear one last time: Yes, most implementations in most browsers won't show the "false" behavior. There is no "it's always right" or "it's always wrong". It is subject to change and it might be different for every browser.

However, good coding practice would dictate that your IComparer implementation should be able to handle being passed the same object in both parameters, as otherwise your implementation is not fullfilling the contract defined by IComparer. It would probably work for your scenario, but you'd be relying on implementation details of the sort method (which might change in the future)

compareFunction
Specifies a function that defines the sort order. If omitted, the array is sorted lexicographically (in dictionary order) according to the string conversion of each element.

Description

If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in lexicographic ("dictionary" or "telephone book," not numerical) order. For example, "80" comes before "9" in lexicographic order, but in a numeric sort 9 comes before 80.

If compareFunction is supplied, the array elements are sorted according to the return value of the compare function. If a and b are two elements being compared, then:

If compareFunction(a, b) is less than 0, sort a to a lower index than b.

If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.

If compareFunction(a, b) is greater than 0, sort b to a lower index than a.

compareFunction(a, b) must always returns the same value when given a specific pair of elements a and b as its two arguments. If inconsistent results are returned then the sort order is undefined

So, the compare function has the following form:
1
2
3
4
5
6
7
8
9

function compare(a, b)
{
if (a is less than b by some ordering criterion)
return -1;
if (a is greater than b by the ordering criterion)
return 1;
// a must be equal to b
return 0;
}

Some implementations of JavaScript implement a stable sort: the index partial order of a and b does not change if a and b are equal. If a's index was less than b's before sorting, it will be after sorting, no matter how a and b move due to sorting.

For sorting strings of languages other than English, use String.localeCompare. This function can compare e, é, è, a, ä, etc. so they appear in the right order.

Sort is stable in SpiderMonkey and all Mozilla-based browsers starting with Gecko 1.9 (see bug 224128).

The behavior of the sort method changed between JavaScript 1.1 and JavaScript 1.2.

In JavaScript 1.1, on some platforms, the sort method does not work. This method works on all platforms for JavaScript 1.2.

In JavaScript 1.2, this method no longer converts undefined elements to null; instead it sorts them to the high end of the array. For example, assume you have this script:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

If all you can show is heavy-handed opinion and articles about other languages, forgive me for not being convinced.

i can't believe this is even debatable to you. Look, all i said is that in one particular case (unique strings), you can get away with using a slightly simplified routine in JS. That can be falsified with a few line of JS. You jump down my throat for that statement and loudly insist that things are as you say can but cannot show. A single observation can falsify my whole theory (if it arises). We're waiting. I stand by my original statement until someone/thing demonstrates otherwise (in javascript of course).

Last edited by rnd me; 03-02-2013 at 10:37 PM.

Create, Share, and Debug HTML pages and snippets with a cool new web app I helped create: pagedemos.com

I wanna bang my head against a wall. What does the language have to do with this? We are talking about the implementation of JavaScript as a language. Which, by the way, typically is a C language.
You are denying the fact that sort algorithms may compare an element to itself and may need to do this, which I provided examples for proving that this is the case. This is a theoretical question about implementation details subject to change, independent of the language in question.

and loudly insist that things are as you say can but cannot show. A single observation can falsify my whole theory (if it arises).

If I'm loudly telling you something, then you are the little child that has its hands over its ears and yells as loud as it can, trying to not hear anything it is being told. I have repeatedly told you things that you keep ignoring, as the quoted sentence once again shows. Him who does not hear can not be taught.

I wanna bang my head against a wall. What does the language have to do with this? We are talking about the implementation of JavaScript as a language. Which, by the way, typically is a C language, but that doesn't matter.
You are denying the fact that sort algorithms may compare an element to itself and may need to do this, which I provided examples to prove the opposite. This is a theoretical question completely independent of the language.

i think you misunderstood me.

I never denied that "sort algorithms may compare an element to itself and may need to" return zero. i even said you usually need to return zero in javascript, probably all the time many languages.

All i said was that zero never comes up on an Array of unique strings.

i'll stand by that.

the user-supplied sort function is not a low-level sort implementation.
otherwise, i'm pretty sure this code block would freeze the browser:

In the case of no-repeat arrays in JS, zero is like "don't ask don't tell" for the user-supplied sort function. i posted the sequence from the ecma5 spec already. and you can trace it out in a debugger using step if you want to see it for yourself.

in the situation i mentioned, the function is never asked for a zero, nor does it return a zero:

the above functions return an array of every return the sort routine created.

it doesn't matter how the underlying browser's implementation operates, the exact sequence of -1s and 1s will be the exact same in all conforming JS engines. if that sequence is the same without or without a (possibly expensive) isEqual comparison, and without zeros, it will run faster while outputting the same thing by never checking equality.

Of course, i should point out that there's really no longer a need to use either code on newer devices (ecma5).

if you look at the spec closely, it says you can pass undefined to [].sort now, and it acts like nothing was passed at all.

in the past, if you passed [1,8,3].sort(undefined), it would throw because "undefined is not a function" or in IE<9: "Array.prototype.sort: argument is not a JavaScript object".

so, i'll go so far as to say that anytime you would use the trick in the example i provided, you should now use undefined instead.

the only situation you would use the shortcut code is on ecma3 devices when you assign the sort routine from an object of different typed sorts, so you don't have to fork your routine to call sort() without any arguments.

that's a small use case for the examples i've show.

the other reason to consider it? performance.

there is a small performance boost in using the shortcut routine:

Code:

function(a,b){return a>b?1:-1 ; }

The above code runs about 5-15% faster on Object.keys(window) in the browsers i tested (ie9+10,ff,ch) than this does:

Code:

function(a,b){return a > b ? 1 : (a < b ? -1 : 0); }

on some sorts, where gathering the compare value is not trivial, forcing a second value comparison can significantly slow down the code.

One example of this is when you are sorting upon a getter property. In that case, and if you know it will never need zero, you can get an even larger performance boost by eliminating 50% of the work load 50% of the time (on avg). This is important because sorting is a bottleneck in many applications where a bottleneck would actually be noticed by the user.

there are other ways to speed up sorting. In cases where there are lots of duplicates, caching the results externally in an object can dramatically help.
for example, sorting rgb pixel values in an image.
yet slows down a sort on an array with little overlap because the additional caching machinery and many cache misses slow down the routine.

in many cases, like getter columns, caching the property inside the sort function for the 2nd equality comparison can help quite a bit. it can avoid the additional function calls for the equality comparison round. If your getter returns a primitive, memorizing it will help you reduce the performance gain of the shortcut routine. (a good thing!)

Create, Share, and Debug HTML pages and snippets with a cool new web app I helped create: pagedemos.com

I never denied that "sort algorithms may compare an element to itself [...] All i said was that zero never comes up on an Array of unique strings.

And that is exactly what I want you to think very carefully about. Even in an array of unique elements, if an algorithm compares an element to itself*, it will be the zero case. And the links I provided do show that some implementations (not in Javascript, but that's irrelevant) may even crash if the case is not handled.

*) Which does not mean comparing it to another element with the same value, it means comparing it to actually the very same object.

You keep asking for examples and maybe it will help to simply point out that I currently can't provide such an example. I will gladly admit that. However, that has never been my point. My point is that the implementation may change in the future, then causing problems. It would be conform to ECMAScript definitions as it does say that the function has to return zero in case of equal elements, it never says that the compare function won't be called with the same element for both arguments.

the user-supplied sort function is not a low-level sort implementation.
otherwise, i'm pretty sure this code block would freeze the browser:

True. I'll agree on that and I do think that it is at least very unlikely that JavaScript will ever crash if you don't return zero. Still, it is a violation to ECMAScript definitions. It typically just isn't a good idea to ignore the specifications you get from implementations you don't have access to.
In web development, we already live in a world full of quirks with every browser doing their own thing and only slowly coming to a common standard. Why add more violations to standards on top of that? Well, you did bring up one point: Performance. Agreed – that's an argument I can accept. However, I'd personally say that you should only violate the specification if performance is crucial at this point of your application (which it isn't in many cases), even if it may potentially break your code in the future.

@ Philipp

Thanks for the correction, I don't know how that slipped past me when re-reading my post before submitting it. However, the glass house saying really doesn't make sense here. I never argued that there wasn't a mistake, nor did I say anything about anyone's grammar.