# collections.sort-by The sort is stable: records that tie on the key come out in the order they went in, in BOTH directions. Descending negates the comparison rather than reversing the list, so the tied block is not silently flipped - that is what makes sorting by one column and then another compose into the multi-column sort a user expects. The total order for mixed values is: booleans, then numbers, then strings, and absent values last. Absent values sink to the bottom in both directions, because 'the rows we know nothing about' belong at the end of a descending table as much as an ascending one; reversing them would put the empty rows first, which no one has ever wanted. A missing key and a null value are the same thing and both sort last. Strings compare by Unicode code point, spelled out rather than inherited: JavaScript's < compares UTF-16 code units and disagrees with Python and Rust above U+FFFF. Comparison is case-sensitive, so 'Zebra' sorts before 'apple'; lowercase the key first if you want a case-insensitive sort. A list or a map at the sort key is an error, and it is detected in one pass before sorting starts. Discovering it mid-comparison would make the error depend on which comparisons that language's sort happened to perform.