The product page had a filter.
Price, lowest first.
It worked in every demo,
because every demo product
cost between one and nine pounds.
Then the real catalogue arrived.
Lowest first
showed a hundred
before twenty five,
and twenty five
before nine.
Nobody had touched the sort.
That was the problem.
The code called sort on an array of numbers
and passed nothing else.
In JavaScript
that does not sort numbers.
With no compare function,
sort turns every element into a string
and orders the strings
character by character.
So 100 starts with a 1,
and 1 comes before 2,
and that is the end of the argument.
[9, 25, 100].sort()
gives back 100, 25, 9.
The specification says so.
It has always said so.
It is the default because
an array can hold anything,
and text is the one thing
everything can be turned into.
Tests with small numbers
cannot see it.
Single digits sort the same
as words or as numbers.
The bug waits for the first value
with two of them.
Pass the compare function.
a minus b for ascending,
b minus a for descending.
It must return a number,
negative, zero or positive.
Not true or false.
a greater than b
looks right,
reads right,
and returns a boolean
that the sort reads as one or zero,
never negative,
so the order comes out wrong
on some inputs
and fine on others.
Use toSorted
when you do not mean
to change the original,
because sort works in place
and returns the same array,
which surprises the next caller.
And for names with numbers in them,
file 2 and file 10,
use a collator
with the numeric option,
so humans get the order
humans expect.
Then add the boring test.
Three numbers,
one of them with three digits,
asserted in the order
a customer would read them.
It is one line.
It would have found this
before the catalogue did.
A default is somebody else's decision
about your data.
Read it
before you inherit it.
– Serguey Asael Shinder
Top comments (0)