Anecdotally, programmers dislike "reduce"
TL;DR
Evan Hahn notices that code reviewers accept map and filter but often flag reduce as hard to read. Hahn offers guesses at the cause, such as readability, familiarity and performance. He asks whether others see the same pattern.
The article
- Hahn uses map and filter constantly, and reviewers rarely comment on them. Patches with reduce often draw a "this part is hard to read" note.
- Hahn also sees reduce in other people's code far less often than map, filter or some.
- Hahn's guesses are that reduce is harder to read, less familiar, sometimes slower than the alternatives, or awkward in JavaScript, Python and Swift. As a Clojure developer, he never got this feedback.
- Hahn usually rewrites the reduce and moves on. He admits the pattern might not be real. He has noticed it less lately, possibly because code review is less thorough now.
Why it matters
The post is a one-minute prompt with no data, so the summary covers nearly all of it. The value is in the thread, which explains the reaction Hahn describes.
The discussion
The thread mostly agreed with Hahn and spent its energy explaining why. The main debate was whether the fault lies with reduce or with how mainstream languages expose it, and functional programmers argued loops are messier. Long side threads covered Python's history with reduce, string-concatenation optimizations and what "filter" even means.
Reduce tells the reader nothing about its result
The most common explanation is that map and filter constrain their output, so a reader knows the result's shape before reading the callback. Reduce can return a scalar, a collection, a tree or anything else, so every call has to be read in full. Several people cited the principle of least power. Use the most specific tool, like sum, groupBy or a plain for..of loop, and keep reduce for when nothing else fits.
Because filter and map are very constrained in what they can do they quickly tell me a lot about the shape of the computation I'm working with. In contrast reduce is much more flexible and so I need to do a much more detailed analysis to just answer a basic question like "is the result a scalar or another collection?".
And even when they don't, *you have to spend effort* to determine that they aren't.
Argument order nobody can remember
The top thread blamed the API. Languages disagree on whether the initial value comes first or last, and whether the callback takes (acc, elem) or (elem, acc). Some also offer a form with no initial value that breaks on an empty collection. TypeScript users described the annotations needed to reduce into an object, and Haskell users traded mnemonics for foldl versus foldr.
Reduce has an accumulator and a 2-arg function and languages are not very consistent amongst each other as to whether it's reduce(initial_acc, callback(acc, elem)) or reduce(callback(acc, elem), initial_acc) or reduce(callback(elem, acc), initial_acc) or what.
In general, I find that if something is hard to describe in plain language, it's hard to code. Reducers are a bit clunky to talk about, which could make them harder to reason about, too.
Quadratic traps in real code
In JavaScript, the `{...acc, [item.id]: item}` idiom copies the accumulator on every step, and one commenter wrote an ESLint rule against it. chubot recalled Guido van Rossum tracing a 30-second page load in Google's code review tool to a reduce over strings. chubot ties that to reduce's move into functools in Python 3, but others cited van Rossum's 2005 post, which complained about readability. A benchmark showed sum and reduce over lists of lists running about 200 times slower than itertools.chain.
So basically Guido spent a long time debugging a performance problem related to reduce(), and made the decision to eject it, to help users avoid "footguns".
Like, why? Not only is this ridiculously inefficient O(N^2), it's also longer and less understandable than "build a new map" version.
The name is the problem
Many argued that "reduce" gives no hint of what it does, unlike map, which is familiar jargon, or filter, an everyday word. It also doesn't have to reduce anything, since it can rebuild a list or grow one. Suggested replacements included accumulate, aggregate, combine, fold and squash. A parallel argument broke out over whether filter keeps or drops matching items, citing Ruby's select/reject, Kotlin's filterNot and Common Lisp's remove-if-not.
What `filter` does is consistent with the word's everyday meaning. But if you don't already know what `reduce` does, it's name isn't even enough to hazard an educated guess.
Defenders: loops are the messier option
A sizable minority likes reduce and blames training, not the function. They argue a for loop mutates outer state, sprawls and invites typos, while a fold with a named callback reads in one line. Others replied that these examples are toy sums, and that real callbacks with caching or metrics read better as a loop. Several noted the dislike fades in Clojure, Elixir or Haskell, where reduce is everyday vocabulary and the loop is clumsier.
You can read one line and know exactly what's happening in the fold example. In the Python and C++ examples, you have to scan more lines *and* there's way more opportunity for typos.
But we don't train people on functional programming at all, so by the time they've built their instincts, passing functions makes no sense to them, immutability is alien, and the idea of a pure function seems irrelevant to them.
Consensus
Hahn's observation holds. Outside functional languages, reduce is harder to scan than map or filter. Its output can be anything, and its argument order varies by language. A named helper such as sum, groupBy or join, or a plain loop, usually reads better.
Dissent
Functional programmers counter that the dislike comes from imperative habits. In their view, a loop that mutates outer variables is harder to reason about than a fold. In Clojure, Elixir or Haskell, nobody objects to reduce.