DEV Community

Discussion on: Stop Telling People For Loops Are Bad

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

Thanks for sharing your view.

I have to say I disagree on your basic premise, though.

The whole purpose of methods such as map, filter and reduce is preventing the mutation of what gets passed into them.

This is a misconception, in my opinion. Although immutability does indeed contribute highly to readability and reduces bugs, the main benefit of this kind of list processing is in how it communicates intent.

With for loops, every example is different. Each loop must be read, parsed, and mentally executed in order for the reviewer or maintainer to understand what it's for (pun!) The only exceptions to this rule are for loops that closely mimic the behavior of map, by deferring their bodies to some function, but even in those cases your stuck with the semantically useless i variable in the body.

Consider

let betterThings = []
for (let i = 0, i < things.length, i++) {
  const thing = things[i]
  const newThing = betterThing(thing)
  betterThings.push(newThing)
}

The only part of line 2 with any semantic meaning is things

By contrast; map, filter, and reduce always mean the same things. They are a shared interface representing classes of procedures. forEach communicates the intent to do side effects, map to mutate, reduce to produce a single value from multiple values.

const betterThings = things.map(betterThing)

To my eyes, this is vastly superior at communicating intent. The amount of verbiage in the first example... Who has time for that?

And remember that the first snippet is the best case of for loop. In most cases, you'll have to read several lines of imperative statements in the body in order to make heads or tails of what's going on.

That being said, just typing .map( won't magically solve all of your readability problems. Naming your functions semantically is key, avoiding lambdas in almost all cases helps.

Ultimately, one needs to adopt the mindset and goal of communicating their intent from the most to least abstract steps, starting at their program's entry point (usually at the bottom of the file) and working their way down.


Now that doesn't mean we should dogmatically forbid all loops. You're right when you say that loops can improve performance in cases. But let's not sacrifice semantics, maintenance, and readability for performance gains which may not be necessary or helpful.

Write semantic, well-abstracted code first. Later, identify and ameliorate performance bottlenecks on a priority basis.

Thanks again for kicking off the discussion!

Collapse
 
beggars profile image
Dwayne Charrington • Edited

This is a great response. You make valid points about these functions communicating intent. I don't think there is anything wrong with these functions because I use them quite a lot myself. It's only when I am dealing with large arrays of data (which is not all too often) that I will choose a for loop.

I agree a for loop where the index is defined in the loop and incremented looks horrendous. I use for..of in combination with Array.entries() these days if I need a loop and the index value.

Your example could be cleaned up considerably using a for..of loop and doing the following:

const betterThings = [];
for (const thing of things) {
  const newThing = betterThing(thing)
  betterThings.push(newThing)
}

You could even go one step further and not bother with the newThing constant and just do this:

const betterThings = [];
for (const thing of things) {
  betterThings.push(betterThing(thing));
}

I am not using Array.entries() here because we don't need the index, we just want the value inside of the array. You can't argue that map does not look cleaner and in this instance, I would also use map as well. If things was comprised of 50,000 things, I might think twice, but a few hundred or even thousand, I would stick with map.

I definitely agree though, as I said at the bottom of the article. Write your code now and optimise it later on if it becomes a problem. Chances are you're only going to incur 100 or so milliseconds using map or any other method, to the point where you or anyone else wouldn't even be able to tell.

Collapse
 
bennypowers profile image
Benny Powers 🇮🇱🇨🇦

So you're saying you have a nuanced and reasonable approach to a twitter-hot-take-bait topic? That's crazy-talk! 😉