skip to content

Contrast in-place sort() / sortWith() on MutableList with the sorted() / sortedWith() copying functions. When would you pick each, and what are the return types and receiver constraints?

level: middleimportance: should knowfreq 55%

answer

  1. '-ed' = copy + return List; no '-ed' = mutate + Unit
  2. sort*/sortWith only on MutableList & arrays
  3. sorted*/sortedWith on any Iterable
  4. In-place saves an allocation
  5. Copying preserves the original / works on read-only

basics

~20 s

sort() and sortWith() rearrange an existing mutable list and return nothing. sorted() and sortedWith() make a new sorted list and leave the original alone. Use in-place to save memory; use copying when the original must stay intact or the list is read-only.

solid answer

~40 s

The in-place functions — sort(), sortDescending(), sortBy { }, sortByDescending { }, sortWith(comparator) — are declared only on MutableList (and arrays). They mutate the receiver and return Unit. The copying functions — sorted(), sortedDescending(), sortedBy { }, sortedByDescending { }, sortedWith(comparator) — are on any Iterable/Array, return a new List<T>, and never touch the receiver. Pick in-place when you own a MutableList, want to avoid an extra allocation, and don't need the original order. Pick copying for read-only Lists, shared/immutable data, or when you need both orders. Both are stable. A common pitfall: calling sort() and expecting a return value (it's Unit), or calling sorted() and forgetting to use the returned list because the original is unchanged.

code

kotlin · 6 lines
kotlin
val original = listOf("b", "a", "c")
val copy = original.sorted()     // [a,b,c]; original still [b,a,c]

val m = original.toMutableList()
val result = m.sort()            // result: Unit; m now [a,b,c]
// original.sort() // COMPILE ERROR: read-only List has no sort()

go deeper

for a junior

Knows there are two variants and that '-ed' returns a new list.

for a middle

States the return types (Unit vs List), receiver constraints (MutableList vs Iterable), and picks correctly by use case.

for a senior

Weighs allocation cost vs preserving the original, mentions stability and primitive-array fast paths.

for a principal

Decides API surface for a library (offer copying for immutability-by-default, in-place only on owned mutable buffers) and reasons about hot-path allocation pressure.

## Two families, two contracts Kotlin separates ordering into **mutating** and **non-mutating** operations, and the naming encodes it: the `-ed` suffix means "copy and return". ### In-place (mutating) — MutableList / Array only ```kotlin val m = mutableListOf(3, 1, 2) m.sort() // m is now [1, 2, 3], returns Unit m.sortDescending() // m is now [3, 2, 1] m.sortBy { it } // by selector, in place m.sortWith(compareBy { it }) ``` These are **not available on a read-only `List`** — `listOf(...).sort()` does not compile. They return `Unit`, so `val x = m.sort()` gives `x: Unit`. ### Copying (non-mutating) — any Iterable ```kotlin val r = listOf(3, 1, 2) val s = r.sorted() // s = [1,2,3], r unchanged val d = r.sortedDescending() val w = r.sortedWith(compareBy { it }) ``` These return a **new `List<T>`**; the receiver is untouched. They work on read-only lists, sets (returning a List), and arrays. ## Choosing - **In-place** when: you hold a `MutableList`, want to avoid allocating a second list (large data, hot path), and the original order is disposable. - **Copying** when: the source is read-only or shared/immutable, you must preserve the original, you need several differently-sorted views, or you're in a functional pipeline (`xs.sortedBy { }.take(5)`). ## Performance & stability Both families ultimately delegate to a **stable** sort (TimSort-style via `java.util.Arrays.sort` for object arrays). In-place avoids one copy; copying allocates a new backing array. For primitives, sorting an `IntArray` in place is cheapest. ## Pitfalls - Expecting `sort()` to return the sorted list — it returns `Unit`. - Calling `sorted()` and then reading the original, expecting it changed — it didn't. - Trying in-place sort on a list produced by `listOf`/`List(...)` — those are read-only.

  • Why doesn't listOf(3,1,2).sort() compile?
    sort() is an extension on MutableList; a read-only List produced by listOf has no sort(). Use sorted() (copy) or toMutableList().sort().
  • What does sort() return?
    Unit — it mutates the receiver in place. Only the sorted*/sortedWith family returns a new List.

In-place sort is reorganizing the books on your one shelf; copying sort is buying a second shelf, arranging copies, and leaving the first shelf as-is.

saying these in an interview costs you the question

  • Assigning the result of sort() expecting the sorted list
  • Calling in-place sort on a read-only List and expecting it to compile
  • Thinking sorted() mutates to save memory
  • Not knowing both families are stable

context