A study about the stability of Array.prototype.sort method on React Native
The
sort()
method sorts the elements of an array in place and returns the reference to the same array, now sorted. And we can also specify a compare function, with that the sorting method is applied. — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
But is the sorting function stable on React Native? Let’s test it.
We say the sorting is stable if it keeps the order of the elements that has same values to compare. Like we apply the sorting function with index
as the sorting key with ascending to an array like
const list = [
{
name: 'name-1',
index: 2,
},
{
name: 'name-2',
index: 0,
},
{
name: 'name-3',
index: 1,
},
{
name: 'name-4',
index: 0,
},
{
name: 'name-5',
index: 0,
},
{
name: 'name-6',
index: 0,
},
{
name: 'name-7',
index: 0,
},
];
and get the output like
const list = [
{
name: 'name-2',
index: 0,
},
{
name: 'name-4',
index: 0,
},
{
name: 'name-5',
index: 0,
},
{
name: 'name-6',
index: 0,
},
{
name: 'name-7',
index: 0,
},
{
name: 'name-3',
index: 1,
},
{
name: 'name-1',
index: 2,
},
];
then we say this sorting method is stable because it keeps the order of the element name-2
, name-4
, name-5
, name-6
, name-7
, that have same sorting key, as they are
On the contrary, the sorting is unstable if it might break the order of elements with same sorting key. It is not saying it would break the order to all possible input, but if there is at least one input that breaks the order, it is unstable.
And then let’s test whether it is stable on React Native?
We can create an example project according to the instruction (https://reactnative.dev/) or follow the tutorial (https://kxie0124.medium.com/implementing-a-sticky-banner-with-animations-in-react-native-df5f619a6bb8).
And add following code in the App.tsx
, just above the return
statement
const list = [
{
name: 'name-1',
index: 2,
},
{
name: 'name-2',
index: 0,
},
{
name: 'name-3',
index: 1,
},
{
name: 'name-4',
index: 0,
},
{
name: 'name-5',
index: 0,
},
{
name: 'name-6',
index: 0,
},
{
name: 'name-7',
index: 0,
},
];
console.log(list.map(item => item.name));
const sortedList = list.sort((a, b) => a.index - b.index)
console.log(sortedList.map(item => item.name));
And then we can run the app with command line
yarn run android
or
yarn run ios
on two platforms.
And we should see the log of input array and sorted array in the terminal that running the metro server like
LOG ["name-1", "name-2", "name-3", "name-4", "name-5", "name-6", "name-7"]LOG ["name-2", "name-4", "name-5", "name-6", "name-7", "name-3", "name-1"]
So it is obvious stable because the order of name-2
, name-4
, name-5
, name-6
, name-7
retains.
But it also said
Since version 10 (or EcmaScript 2019), the specification dictates that
Array.prototype.sort
is stable. Before version 10 (or EcmaScript 2019), sort stability was not guaranteed — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
But is it stable on older React Native versions? Let’s test it.
Firstly we can check the React Native version from the package.json
, then we can find the react native version of this project is 0.69.4, latest version so far.
Let’s create another project with older React Native version, like 0.64. We can run following command to create project with specific React Native version
npx react-native init sorting --template react-native-template-typescript@6.6
We can find the table at https://www.npmjs.com/package/react-native-template-typescript
And then we build the app with same modification and run it, we would find the sorting function is also stable.
So we can make a simple conclusion that the sorting function is stable with default JS engine because we all know the JS code is running on JS engine on React Native.
But how about other JS engine, like Hermes. We all know the Hermes engine has better performance, but with some cost.
Ok. Let enable Hermes engine as https://reactnative.dev/docs/hermes
And rebuild and run the app again, we would find the it printed
LOG ["name-1", "name-2", "name-3", "name-4", "name-5", "name-6", "name-7"]LOG ["name-4", "name-5", "name-6", "name-7", "name-2", "name-3", "name-1"]
The order of elements with same sorting key changes. It is not a stable sorting.
So it is obvious an issue of Hermes engine.
How about other version of Hermes engine. But unfortunately, the Hermes engine version is bundled with React Native version as https://github.com/facebook/hermes/releases
So we need to upgrade React Native first with command
npx react-native upgrade x.xx.x
We can find React Native release versions at https://github.com/facebook/react-native/releases
After testing several versions, we would find the Hermes 0.11 on React Native 0.69.4 fixed this unstable sorting issue.
Actually, this issue is also addressed at https://github.com/facebook/hermes/issues/212.
So case closed.