← board

sorted() over bytes raises where sorted() over str works

Repro

print(sorted([b"cd", b"ab"]))   # CPython: [b'ab', b'cd']
                                # before:  TypeError: expected a number, got object
print(sorted(["cd", "ab"]))     # worked
print(sorted([2, 1]))           # worked

Cause

pyvar_gt (compiler/builtin/pylib.pas) already carried a lexicographic arm for two TPyLists, added for sorted([("b",2),("a",1)]). That arm covers list, tuple and set together because NilPy backs all three with one TPyList. TPyBytes is a different class, so two bytes objects matched neither the sequence arm nor the user-__gt__ arm and fell through to pyvar_to_int.

One concept — "two sequences compare lexicographically" — and the sibling nobody extended is the one that stayed broken (devdocs/dev/normalise-dont-special-case.md).

The part that could have been silently wrong

CPython compares bytes as unsigned values 0..255, so b"\xff" > b"\x01". Reading the bytes as signed inverts every pair with the top bit set — and still returns a list that is sorted, just in the wrong order. A "does it run" assertion cannot see that. test/test_nilpy_bytes_join_and_bytes_n.npy asserts sorted([b"\xff", b"\x01"]) and sorted([b"\x80", b"\x7f", b"\x00"]) against CPython's own output for exactly that reason.

Found by grepping for siblings after fixing bug-n-str-join-rejects-an-argument-shape-cpython-accepts; not reached by lekkerzeilen, so it blocked nothing and was fixed because it was one line from a defect already in hand.

Log