Skip to content

Taxonomy

Mutation of a caller's input

The function rewrites a value somebody else is still holding.

What it looks like

  • .sort(), .reverse(), .splice() or .push() on an argument.
  • A defensive .slice() or spread removed as 'an unnecessary allocation'.
  • Object.assign(input, …) where a new object was intended.

Why it survives review

The function returns exactly the right answer. Every test of *this* function passes, because the damage is not to the return value — it is to a value the caller still has a reference to. It shows up as a bug in an unrelated part of the system, later, and nobody connects the two.

How to see it

  1. sort and reverse mutate. map, filter and slice do not. Know which is which and check every call against an argument.
  2. For each parameter, ask whether the function writes to it, and whether its caller would be surprised.
  3. A removed copy in a diff is a behaviour change even though the returned value is identical.

A minimal pair

Correct

const ordered = items.slice().sort(byDate);

Defective

const ordered = items.sort(byDate);

Both return the same sorted list. The defective build also leaves the caller's array sorted.

Practise it

2 diffs in the corpus carry this class. They are not listed, because knowing which diff contains what would make finding it a comprehension question about this page.

Go to the exercises