You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Array.sort arguments order changed in Node.js 11 #24294
Platform: Darwin hubert.local 18.2.0 Darwin Kernel Version 18.2.0: Fri Oct 5 19:41:49 PDT 2018; root:xnu-4903.221.2~2/RELEASE_X86_64 x86_64 (macOS 10.14.1)
Subsystem:
Hi!
I've noticed a change with Array.sort(). In Node.js 11 order of arguments passed to compare function is reversed. While in most cases it's not a problem, in some cases it causes problems.
Hello @hudochenkov, and thank you for the report.
As you mention, this is a change node get by way of a update V8. There was some discussion on the implication of the new algorithm #22754 (comment), but AFAIK this specific issue was reported for node
@hudochenkov stable sort means what if elements in the unsorted array were already in the correct order, they are guaranteed to be in the same order after sorting.
in any case, as long as you always return the correct number for two elements, no matter the order, the engine will properly handle it. if the engine switches the order of the arguments, it will also handle the switched return value.
Array#sort is returning the correct result, just like before the change in V8. This report is not about a spec correctness issue.
The order in which the elements are compared during sorting (and similarly, how many times the comparison function is called in total) is intentionally unspecified, and depends on the exact implementation. When the V8 implementation changed from QuickSort to TimSort, this order changed. But that’s the thing: this order wildly varies across implementations, and even within the same engine it can change at any point; developers shouldn’t rely on it. This is explicitly called out in https://v8.dev/blog/array-sort#accessors-prototype.
This is not a regression; it’s an implementation detail that shouldn’t be relied upon.
Reacted by snek, Refael Ackermann, Ujjwal Sharma, Frieder Bluemle, Regan Karlewicz and Haotian Chai
@refack, let me respond to your test case now. This program demonstrates something separate from the issue OP reported. The sort callback in this code example is what the spec calls an inconsistent comparison function. For example, assume the following values:
a = { p: 'x', id: 3 }
b = { p: 'bottom', id: 4 }
Now, given the way sortDeclarations is written, we can observe the following:
if you compare a with b, sortDeclarations returns 1
if you compare b with a, sortDeclarations returns 4 - 3 which is… also 1
The result of a sort with an inconsistent comparison function is implementation-defined, and cannot be relied upon. In other words, this too is WAI.
@JJBocanegra That's because your comparison function is inconsistent. It returns -1 for both check(members[0], members[2]) and check(members[2], members[0]). A better comparison would be this:
@addaleax I don't think it's a bug in my code, what If I want to use the initial order as a secondary sorting like is the case? With the arguments inverted is not possible without modifying the initial data adding some kind of index because other browsers use the correct arguments order.
@JJBocanegra you could return 0 instead of return a.id - b.id The point is that if both items have the same isAdmin value, they need to compare consistently by some other metric.
Reacted by Anna Henningsen and José Joaquín Bocanegra
Activity
richardlau commentedon Nov 10, 2018
It's intentional: #22754 (comment)
refack commentedon Nov 10, 2018
Hello @hudochenkov, and thank you for the report.
As you mention, this is a change node get by way of a update V8. There was some discussion on the implication of the new algorithm #22754 (comment), but AFAIK this specific issue was reported for node
/CC @nodejs/v8 (esp. @targos @hashseed @mathiasbynens)
refack commentedon Nov 10, 2018
P.S. @hudochenkov can you provide some data that using your code sorts differently?
devsnek commentedon Nov 10, 2018
@hudochenkov stable sort means what if elements in the unsorted array were already in the correct order, they are guaranteed to be in the same order after sorting.
in any case, as long as you always return the correct number for two elements, no matter the order, the engine will properly handle it. if the engine switches the order of the arguments, it will also handle the switched return value.
hudochenkov commentedon Nov 10, 2018
Thank you for quick replies!
I'll simplify my sorting function as much as possible and will provide examples of how it sorts differently. I'll do it tomorrow.
refack commentedon Nov 10, 2018
refack commentedon Nov 10, 2018
simpler code:
Get me:
mathiasbynens commentedon Nov 11, 2018
Array#sortis returning the correct result, just like before the change in V8. This report is not about a spec correctness issue.The order in which the elements are compared during sorting (and similarly, how many times the comparison function is called in total) is intentionally unspecified, and depends on the exact implementation. When the V8 implementation changed from QuickSort to TimSort, this order changed. But that’s the thing: this order wildly varies across implementations, and even within the same engine it can change at any point; developers shouldn’t rely on it. This is explicitly called out in https://v8.dev/blog/array-sort#accessors-prototype.
This is not a regression; it’s an implementation detail that shouldn’t be relied upon.
mathiasbynens commentedon Nov 11, 2018
My above comment was in response to the gist in the OP, i.e. https://gist.github.com/hudochenkov/29b739f8dbdb4aa00a46b953f62dd0a6.
@refack, let me respond to your test case now. This program demonstrates something separate from the issue OP reported. The sort callback in this code example is what the spec calls an inconsistent comparison function. For example, assume the following values:
a = { p: 'x', id: 3 }b = { p: 'bottom', id: 4 }Now, given the way
sortDeclarationsis written, we can observe the following:awithb,sortDeclarationsreturns1bwitha,sortDeclarationsreturns4 - 3which is… also1The result of a sort with an inconsistent comparison function is implementation-defined, and cannot be relied upon. In other words, this too is WAI.
hudochenkov commentedon Nov 11, 2018
Thank you for investigation, @refack! And thank you for clarification, @mathiasbynens!
I guess I was just lucky with my sorting function all these years :) I'm going to rewrite it to be independent of arguments order.
32 remaining items
JJBocanegra commentedon Aug 6, 2020
If I do that, then in Firefox browser it will be with the wrong order, because it uses the normal parameters order.
Take this example to get the admins at the beginning of the list:
It will return order them by these IDs in Chrome
3, 1, 2and by these in Firefox1, 3, 2devsnek commentedon Aug 6, 2020
@JJBocanegra That's because your comparison function is inconsistent. It returns
-1for bothcheck(members[0], members[2])andcheck(members[2], members[0]). A better comparison would be this:JJBocanegra commentedon Aug 6, 2020
@devsnek But that's implying that I want to order by ID, but I do not, I want the initial order to be respected. Consider this:
I want the final order to be
And with your suggestion it would fail too.
addaleax commentedon Aug 6, 2020
@JJBocanegra Can you open a new issue at https://github.com/nodejs/help/issues/ instead of discussing this one?
JJBocanegra commentedon Aug 6, 2020
@addaleax sure, but isn't it better to have it here because is directly related to the issue?
addaleax commentedon Aug 6, 2020
@JJBocanegra As @devsnek said, this is a bug in your code. It’s not really related to this issue here.
JJBocanegra commentedon Aug 6, 2020
@addaleax I don't think it's a bug in my code, what If I want to use the initial order as a secondary sorting like is the case? With the arguments inverted is not possible without modifying the initial data adding some kind of index because other browsers use the correct arguments order.
devsnek commentedon Aug 6, 2020
@JJBocanegra you could
return 0instead ofreturn a.id - b.idThe point is that if both items have the same isAdmin value, they need to compare consistently by some other metric.reimplement noncommutative sort
Discovered an issue with sort with node v10 - nodejs/node#24294 - fixed
Add reference to nodejs/node#24294
Fix sorting back compatibility nodejs/node#24294
reimplement noncommutative sort
reimplement noncommutative sort
fidellucene commentedon Oct 10, 2025
https://contribution-guttural8.github.io/jai/
Check out the response here