8 ms·
Why so much hate for loops? Loops are just a nice notation for some computational constructs. Sometimes they are the clearer way to write an algorithm. Very
by enriquto 5y ago
Why so much hate for loops? Loops are just a nice notation for some computational constructs. Sometimes they are the clearer way to write an algorithm. Very often an algorithm becomes clearer when written in explicit loop form than in "vectorial" notation.
Loops do not need to be artificially slow to discourage them. Any modern programming language should be able to recognize the construct and compile it in the most efficient way. Saying that you must avoid loops because they are slow is a failure in a particular programming language, not in the concept of loop. After all, all languages managed to implement loops efficiently many decades ago.
- GerbilWithALisp 5y agoI don't use loops because they force you to use side effects in your code.
- mekkkkkk 5y agoI think the idea is that a loop in many cases doesn't express your intent. What you might want to do is to "set the property 'foo' to 'bar' on all items in an array". What you might write is "create a variable and set it to zero, then iterate that variable as long as it's smaller than the number of items in the array, and do this between each iteration: take the item at the variables index and set its property 'foo' to 'bar'". Of course any programmer will instantly see what's going on, but that's not from clarity but from prior experience and familiarity.
- rand_r 5y agoThis seems perfectly clear. for item in array: item.foo = bar
- maest 5y agoarray.'foo = bar Is clearer. Or, at least, would be, if one were accustomed to the (fictitious) adverb '. There's no need for all the ceremony around specifying "for x in y: <some function describing what to do with x>"
- deleted 5y ago[deleted]
- jcelerier 5y agoIt isn't. "For x in y" is literally what we say when speaking as humans unlike that quote thing.
- maest 5y agoI don't find that to be a convincing argument, because it suggests we should write "foo applied to bar" instead of "foo(bar)" in your code. It's just notation, just because it's new, doesn't mean it's bad. There's maybe an argument to be made about there being _too much_ notation to learn, but notation makes sense for fundamental concepts (which loops clearly are). Notation is important. It condenses thought and refines the concepts, making them more visible. In fact, some valid mathematical theory came about from figuring out proper notation and then playing around with it, sometimes in non-rigorous (albeit intuitive ways). e.g. consider how physicists wildly move dx and dy around in differential equations (much to mathematicians' dismay) Ancient greek geometry textbooks were written in long form: "the square of the hypotenuse side is equal to the sum of squares of the other two sides". We can all agree that the "a^2+b^=c^2" notation is better.
- mekkkkkk 5y agoThat's an awkward way to speak. "Take each of my gizmos, then put it in the gizmo box" for gizmo in gizmos: gizmo.put_in_box() vs "Put all my gizmos in the gizmo box" gizmos.'put_in_box()
- pletnes 5y agoWith numpy, this would just be item.foo [:] = bar. Much more readable to me - the whole «for» thing is superfluous.
- maest 5y agoNeat trick. Didn't know about it. In pandas it would be item.foo = bar, _as long as_ bar isn't something you can iterate over.
- pletnes 5y agoNumpy is all about this. E.g y = np.sin(x). X and y are arrays and you can think of them as «all values of x and y» or «the physical variables x and y»
- jbluepolarbear 5y agoThese comments from people who don’t write software and only use programming for data science. Numpy is superfluous for anyone that doesn’t need it.
- kergonath 5y agoIndeed. Also, this notation was lifted straight from Fortran 90 (which itself got it from Matlab, Algol, and the primitive slicing that was possible in older FORTRANs). The idea that a concise notation is helpful for the concept of “put a thing in all the buckets of an array” really is quite old. It does make a lot of sense.
- convolvatron 5y agothere is also a pretty big difference in what a compiler can do if we express the computation as a set of operations that transform the sets rather than a little rats nest of mutations and jumps. if you wanted to vectorize the set/jmp version, you'd be trying to tease apart a problem which is undecidable in the limit. vectorizing the transformer version is trivial.
- kristjansson 5y agoThere’s also the reverse: writing as a loopless operation forces the programmer to write code that can be easily vectorized.
- FalconSensei 5y agoIn python, the way you write this is more similar to how we express the intent, using dict/list comprehension. But the thing is, for anything more complex that your example, the comprehension notation is harder to read and make changes if you are not really used to it
- BeFlatXIII 5y agoPythonic for loops are more or less `for item in list: <block of code>`. Sill no manual management of array indices.
- dagmx 5y agoThat's only true for languages that don't support looping over an iterable directly. Or if you need the index while iterating too. Python, Rust, Swift, C++, ObjC and more all support the equivalent of a foreach loop today. That perfectly shows intent
- jakear 5y agoAgreed, and based on the list here: https://en.m.wikipedia.org/wiki/Foreach_loop https://en.m.wikipedia.org/wiki/Foreach_loop the only popular language without for each is C.
- CuriousCosmic 5y agoAnd even then, a decent number of data structures provided in headers on *nixes provide for each macros.
- tomtomtom777 5y agoTrue. It is possible though for a language to avoid these iteration constructs as if they are needless plumbing as well. Consider the elegant type system of the XQuery language: In XQuery, the root type is a flattened sequence. Flattened means not just that [1, [2, 3]] is flattened to [1, 2, 3], but also the a single object 42 is equivalent to a sequence of one object [42]. This means that if I write: declare function local:prefixName($name) { fn:concat("prefix-", $name) } I can invoke it with a single name or a sequence of names without any explicit iteration. It has drawbacks but using XQuery certainly highlights how much code we normally waste dealing with "things" and "sequences of things" separately. (Than again working with XQuery also highlights how much code one can waste dealing with XML namespaces :)
- mekkkkkk 5y agoAdmittedly it's a worst case scenario, but the broader point still holds even with a foreach. You are still picking out each item individually instead of operating on the collection which is what you intend to do. You write "do this for every apple: peel it", instead of "peel the apples".
- rickbdjvdjb 5y agoThe PLT position on this is that loops are too expressive. We'd like to use the least powerful tool that can do the job. Loops can express all sorts of incorrect versions of the intended algorithm. It's preferable to try to identify the reusable structure in the algorithm (it might be a "scan" or a "fold", for example) and implement that once and for all. We then provide a simple interface to that algorithm, without any footguns.
- dgb23 5y agoThat's like saying a bag is too expressive because I can put all kinds of things into them.
- maest 5y agoMore practically, a List is too expressive, if all you need is a Set - which is true and generally good advice to use Set instead of List, if possible.
- enriquto 5y agoFrom what kind of programming hellhole do you come from, where using Set instead of List is good advice? Lists are very natural constructs for computers, sets aren't.
- RHSeeger 5y agoA set implies a uniqueness constraint that a list does not. Generally a list is ordered by contract, whereas whether or not a set is ordered depends on the implementation.
- Jtsummers 5y agoSets specify a particular interface but not a particular implementation or backing data structure. You can substitute different implementations (including ones backed by lists, vectors, hash tables, and others) depending on your particular needs.
- 5y ago
- maest 5y ago> Why so much hate for loops? I don't think there's any _hate_ for loops, however, they are a very common pattern, so it's not unreasonable to argue it can be further refined/abstracted. Most people agree that "for x in y: foo(x)" is an improvement over "for(int i=0; i<=n; i++) {foo(x)}". It's not wild to argue that "foo' x" is an improvement over "for x in y: foo(x)"
- enriquto 5y ago> Most people agree that "for x in y: foo(x)" is an improvement over "for(int i=0; i<=n; i++) {foo(x)}" Well, I don't. The second version is much clearer to me, for example, if I want to be sure about the running time of the code. Will it take one second or be instantaneous? The first example hides the length of y. I favor a programming style where all loops have clearly identifiable bounds. Using "iterators" hides these lenghts and makes the code much harder to reason about.
- the_af 5y ago> The second version is much clearer to me Clearer? Did you notice the second version contains a bug? The first version makes it easier to spot said bug, because it's more concise and with fewer parts where you could make a mistake. Note that even in this very short piece of code it's easy to miss the bug; imagine in actual loops! You have no guarantees about the running time of the code in either case, not without delving into the specifics of your programming language. > I favor a programming style where all loops have clearly identifiable bounds. Using "iterators" hides these lenghts and makes the code much harder to reason about. I find the opposite to be the case. Explicit loops with indexes make off-by-one errors likely, which is one of the most common kinds of error. It's impossible to make that kind of mistake with a foreach or map-over-this operation.
- maest 5y ago> Did you notice the second version contains a bug? Whoops - in my defence, I haven't coded in C in a very long time. I'll leave it there, since I think it makes an (unwittingly) good point.
- p2t2p 5y agoFor me at comes down to telling "how" instead of "what" to do.
- 8note 5y agoLoops imply that the order matters when it doesnt. When order does matter, loops are quite enjoyable
- math-dev 5y agoThanks, this was a good post and worth skimming through all the other nonsense to get to
- pfortuny 5y agoOh but in J loops exist, they are mostly implicit in the operation. So it is not “loopless” per se, as the sigma notation for summation indicates a loop in a single construct, and it “can be written away” using Einstein’s notation. That is how it should be understood, imo.
- mirekrusin 5y agoLoops are great if your programming languages supports iterables/iterators/generators (also async generators) like in js/ts for example. Especially generator-to-generator combinators ie. [0] gives terse, transducer expressiveness over computation on finite/infinite streams, arrays, etc. (all iterables). It's easy to compose, jump into/out-of for-loops if needed for arbitrary yielding (ie. conditionally yielding multiple items, skipping some, halting etc); `continue`, `break`, nesting, yield, yield from (yield*), normal code in for-loops is very intuitive and terse, creating pleasant, understandable code. Recently I had a chance to break down complex pipeline in finance project into small steps as generator-to-generator transducer functions (can you call generator-to-generator functor a trasducer?), higher order for steps that require extra inputs, leaving all pipeline pure and easy to reason about. Typescript was really helpful doing hard work where each step somehow modifies the input - leaving final result typechecked together with spotting bugs in intermediate steps ie. on their dependendency etc. really nice stuff. [0] https://github.com/preludejs/generator https://github.com/preludejs/generator
- pasquinelli 5y agoif you're not writing explicit loops then you must be doing something else. is that something else interesting? you'd have to dig in a little bit to find out.
- dragonwriter 5y ago> Why so much hate for loops? Well, for me, because, compared to other notation, they usually obscure intent. > Loops are just a nice notation for some computational constructs. But... they're mostly not. > Loops are just a nice notation for some computational constructs. Sometimes, but even then if a language has decent abstraction features that’s usually best for the low-level implementation of a generic algorithm, which you should never have to see when actually applying the algorithm to concrete types. True, if you don't have a generic implementation available, YAGNI often argues in favor of a concrete one for the immediate use case, so generic implementations separated from immediate concrete use isn't the only place to use explicit loops.
- gnufx 5y agoNot hate for loops, but if you replace them with, say, array operations, you've removed the need to prove your loops correct -- or removed a possible source of error from getting them wrong. I guess what's clearer is a matter of opinion. Reconstructing what was meant at high level from arbitrary loops is surely intractable, but could only be a property of a compiler, not a language. Should a compiler like GCC necessarily recognize a matmul loop nest and replace it with a GEMM call? XL always does -- which can make investigating it's optimization annoying -- but then it doesn't actually recognize GEMM.