9 ms·
Go one step further, eliminate the polyfill, and just write a traditional for loop. Several years ago, I decided to try out the then-newish E4X for-each syntax
by carussell 9y ago
Go one step further, eliminate the polyfill, and just write a traditional for loop.
Several years ago, I decided to try out the then-newish E4X for-each syntax. It was only implemented in SpiderMonkey, but that was okay because not only am I not a web developer, this project wasn't meant to run on the web, either—it just happened to be in JS. I knew for a fact that this code wouldn't be running anywhere except SpiderMonkey, so I dug in. After some research, though, I discovered some problem. Some subtlety that made it a non-starter. So I kept writing traditional for loops.
A couple years later, I was starting work on a kind-of-new codebase; it was essentially greenfield, but I knew I was going to end up cribbing a bunch from an existing codebase. When my fingers began typing out the familiar `for (`, I paused. This would be the first for loop introduced in the project, and I should maybe make a decision to get things right from the beginning. By now, for-of had arrived, and it was being standardized in ESx proper. Should I maybe do another survey of the lands and look into giving the new iteration syntax a shot? It was a simple iteration: a straight pass through a list of items, one after another. And in addition to being able to address items by index, they all had the equivalent of a "next" pointer for the item that followed. So I deferred; I went with a while loop instead, chasing "next" pointers to avoid having to do some in-depth research on the then-current state of `for`. I got pretty far doing this, actually, and was able to go the next few days writing all my loops in this way, just to avoid tacitly endorsing either for-of or traditional for loops.
After several days, however, that ran out, and I came to point where I would not be able to sidestep it and needed to make a decision. So I stopped, and dug in again. Another problem surfaced: for-of was only implemented in the newest releases of SpiderMonkey, and the only enhanced iteration syntax available in previous releases that this code would need to run on was the now-deprecated for-each. I thought really hard about this. Was there some part of the language that could be exploited to find some clever way around this? No. Maybe consider a transpiler? After all, for-of would be standard, so eventually support is going to be widespread enough that even the lowest common denominator will have native support...
But then I stopped. Because the whole thing is stupid. Just write a damn for loop. What was the real problem? Trying to save time? Except how much time was already sunk into trying to shave off, what? Like one second of typing? Maybe two? And the tradeoff for that development time gain is (a) a runtime performance penalty; (b) having to either throw everything older than version x by the wayside or spend all those extra seconds and more to put some transpiler crud in place; and (c) code that's harder to understand for anyone who doesn't fetishize staying on top of the newest language features. The latter also involves people who typically work in other languages and would probably immediately understand `i = 0; i < n; i++` (even if it's not idiomatic for their preferred ecosystem), but likely wouldn't immediately grasp the nuances of the new iteration protocol.
What's wrong with `i = 0; i < n; i++`, anyway? It's not even that verbose. What it is, is predictable. Which means your eyes get used to it, just like any other pattern. Except traditional for loops are powerful, too, because you might want to do something, say, for every fourth item. Or maybe skip the first. Or iterate backwards. And you can. In each case, anything not fitting the traditional pattern will stick out.
Anyway, I still write traditional for loops today. I don't feel like I'm missing out on anything, and my thoughts very much echo the sentiments in an essay published a few years ago on a similar topic: "Java for Everything".
https://www.teamten.com/lawrence/writings/java-for-everything.html https://www.teamten.com/lawrence/writings/java-for-everythin...
- torgard 9y agoOne point towards using Array prototype functions (map, filter, reduce, etc.), is that they are often much more readable. For loops are harder to skim. Still, I don't understand the for loop hate. I have seen people argue against 'pointless optimizations', in the name of readability. And while yeah, arr.filter().map() is probably faster to comprehend, you're still iterating through the array twice. Pointless optimizations, not so much when the array is thousands of elements long.
- yxhuvud 9y agoIterating a long array twice to do two simple things can often be faster than iterating once to do a more complicated thing. See for example https://stackoverflow.com/questions/8547778/why-are-elementwise-additions-much-faster-in-separate-loops-than-in-a-combined-l https://stackoverflow.com/questions/8547778/why-are-elementw... . The wonders of modern processors and compilers.
- taeric 9y agoThat link is more about the pitfalls of page alignment. Caches being a very dangerous topic. Getting the data aligned in a cache friendly way returns those loops to the expected behavior of one iteration being faster than two.
- ComputerGuru 9y agoI’ll never understand this. JavaScript’s threading model (none) makes it ridiculously easy to implement coroutines/iterables so that map, filter, and co can be efficiently written. How did Microsoft manage to realize the necessity of coroutined iterables in a threaded, impure, multiprocess-capable language like C# (without breaking backwards compatibility, might I add) with Linq, and yet JavaScript couldn’t? (If I may be permitted to go slightly off topic here, I also think it’s a damn shame Rust devs were so eager to release v1.0 of their shiny, new language to attract the masses that Rust - the language, not stdlib - shipped without native concepts to accommodate iterables and async/await. Unthinkable this side of 2010 for a language that aimed to be the second coming of C++).