Kotlin Sorting Under the Hood: Why Reading Source Code Still Beats AI Guesswork
AI coding assistants produce working Kotlin that often ignores whether a list supports random access, recomputes expensive sort keys inside comparators, or calls terminal operations on infinite sequences. Knowing the internal dispatch paths lets an engineer spot the performance regression before it ships.
Kotlin's `sorted()`, `reversed()`, and `shuffled()` functions look interchangeable at a glance but rest on fundamentally different implementations. `sorted()` branches on whether the receiver is a `Collection` or a plain `Iterable`, converting to an array when size is known to avoid repeated allocations. `reversed()` and `shuffled()` similarly create mutable copies before operating in place, while `asReversed()` returns a zero-copy view that tracks changes to the original list.
On the JVM, these functions delegate to `java.util.Collections` routines that inspect whether a list implements `RandomAccess`. `ArrayList` gets direct index swaps; `LinkedList` gets iterator-based traversal to avoid quadratic degradation. The Fisher–Yates shuffle and TimSort-backed stable sort are both platform details that a developer relying solely on AI suggestions would never see.
A `sortedBy` selector can fire many more times than expected because `compareBy` calls it on every comparison, not once per element. Expensive key computation inside that lambda, integer subtraction in a `Comparator`, and calling `sorted()` on an infinite `Sequence` are all real-world mistakes that surface only when you understand what the standard library actually does.
AI code generators optimize for correctness of output, not for the cost path — they will happily put a database call inside a `sortedBy` lambda because the API shape is legal.
The `sortedBy` selector trap is a perfect example of a leaky abstraction: the function reads like a map-then-sort but behaves like a sort-with-repeated-evaluation, and only reading the source makes that clear.
Kotlin's naming convention (`sorted` vs `sort`, `reversed` vs `reverse`, `shuffled` vs `shuffle`) encodes mutability in a single letter, but the real complexity is in the JVM delegation that inspects `RandomAccess` — a detail invisible from the Kotlin side.
The warning about infinite sequences and `sorted()` is not academic; lazy collection pipelines make it easy to accidentally attach a terminal-like sorting operation to an unbounded stream, and the failure mode is a silent hang rather than an exception.