DEV Community

loading...

Discussion on: Don’t pay the for-loop tax

Collapse
richardtallent profile image
Richard Tallent

Ok, I'm gonna be the old fart here.

  1. If anything has a "tax," it's using map/reduce/filter, because these require defining a function (frequently an anonymous one) to perform the unit work, then that function is called for each iteration. So for N loops, you get at least N+1 additional function calls, with all of the associated overhead, compared to just having some code in a loop.

  2. Calling map/reduce/filter doesn't eliminate the for loop, it merely moves it. The implementation of these methods has... you guessed it... a for loop.

  3. Loops can break or return early. While findIndex() helps with some situations you'd need that for, other use cases don't have an equivalent.

  4. Loops can modify their iterator variable, allowing them to skip over values (or even go back). Granted, this is an edge case.

I suppose the idea is that loops somehow require a mental tax? I've been using "for" and its siblings for over 30 years in just about every programming language, so they're pretty natural for me.

I do use these abstractions, and enjoy the syntactic sugar where it makes sense. But avoiding a loop structure should be a choice made with a full understanding of the pros and cons, it shouldn't be some sort of default because "indentation is a code smell" or similar hair-brained rules.

Collapse
joshcheek profile image
Josh Cheek

So for N loops, you get at least N+1 additional function calls, with all of the associated overhead, compared to just having some code in a loop.

I may be wrong, but I would have assumed that modern JS interpreters can optimize this away. I would also expect it to be faster to call the loop they implement in the underlying language.

Calling map/reduce/filter doesn't eliminate the for loop, it merely moves it. The implementation of these methods has... you guessed it... a for loop.

If you're iterating over an array, but not necessarily for other iterable structures. A nice thing about using the iterator functions is that you don't have to know / care what kind of collection you're iterating over. Using the abstractions means you don't have to embed iteration knowledge at every location in your code that you want to iterate. Your code doesn't change just because the details of how to iterate change.

Loops can break or return early. While findIndex() helps with some situations you'd need that for, other use cases don't have an equivalent.

IIRC, there's an interface for defining iterators that allows them to return early.

Loops can modify their iterator variable, allowing them to skip over values (or even go back). Granted, this is an edge case.

It's a good point, if you can't do that, then you have to retain state somehow (probably via a stack). Although, if the logic for how to prepare for the next iteration were that complex, I would probably choose a while loop over a for loop (or perform the update section of the for loop in its body).

Collapse
maxart2501 profile image
Massimo Artizzu

Indeed, the performance penalties of functional programming methods must be known, but you're misunderstanding what's the "tax" here: it's indeed a "mental" tax, which led us to use old patterns because they were the only ones available in older languages, and they're still available anyway, while there could be other, more expressive ways to do the same things.

More expressivity means the code is more readable and maintainable, because it gives you more hints about the purpose of the code. If that implies writing a separate function for the iteration, so be it, because it's exactly the function's name that brings additional value.

Sure, you can always write a comment. But comments should explain why, not what: writing comments is tedious, so let the code speak for itself as much as possible.

Collapse
danhomola profile image
Dan Homola Author

Thanks for the reply. I'll try to comment on your points:

Ad 1. The tax was originally meant as a real monetary tax (or a fine more precisely) and it was meant as a joke. There were no performance connotations to the word in this context. As others have stated in this thread: if you need performance go for the loops.

Ad 2. I agree, but it hides it from you, and I believe it is a good thing. When reading someone else's code, I'd much rather see a map than some loop because with the loop I have to infer the what from the how whereas with map the what is already written for me.

Ad 3. So can find, includes and some others. Granted these are not as widely supported, they can be polyfilled.

Ad 4. I think that is actually a disadvantage, just because you can do something, doesn't mean you should (excluding the performance optimisation scenarios).

I totally agree with you on that any choice should be made with all the implications in mind. The approaches recommended in the article are just that – recommendations :)

Collapse
t0ss_games profile image
t0ss

You pretty much covered what I was going to comment here. I'm honestly a little skeptical of some of the mantras surrounding Javascript at the moment. There are some ideals being tossed around at the moment that might lean a bit too hard on perceived "readability advantages" and straightforwardness. In other words, the performance implications of some of the current proposed best practices make me a tad uncertain regarding their longevity.

edit: I'm not saying the giving examples are bad either, I feel like this piece actually gave great examples. I'm speaking towards the bigger trend I've been noticing.