8 ms·
That'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++, Ob
by dagmx 5y ago
That'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".
- tshaddox 5y agoapples.forEach(peel) is pretty clear, and the distinction is actually important for some operations which could conceivably be applied either to the whole collection or to each item in the collection and thus could be ambiguous in plain English, like “gift wrap the apples.” That could mean giftWrap(apples) or apples.forEach(giftWrap).
- Kinrany 5y agoHere's another comparison: peel and add to mixer fresh apples only. let mut mixer = Mixer::empty(); apples.for_each(|apple| { if apple.is_fresh() { mixer.add(apple.peel()); } }); let mixer = apples .filter(Apple::is_fresh) .map(Apple::peel) .fold(Mixer::empty(), Mixer::add);
- conradludgate 5y agoThey're both pretty clear but I'd prefer the second one (if you used collect instead of fold)
- Kinrany 5y agoI chose Rust syntax because it allows both chaining and using methods as functions, but avoided Rust-specific features. In addition to `collect` this example is missing `.into_iter()` that both examples would need: I interpreted `apples` as an iterator instead. Otherwise the first example would be clearer with a for loop.
- IggleSniggle 5y agoWell said! And when this clarity is lacking in a codebase, damn do I find it incredibly frustrating! Like, can’t you just tell me whether you are trying to operate on the items of the collection or the collection as a whole??? Why did you need to adopt this ambiguous formation??
- mekkkkkk 5y ago
- dragonwriter 5y ago> That's only true for languages that don't support looping over an iterable directly. Even with loop-over-iterable semantics, explicit loops obscure intent compared to comprehensions and map/reduce/filter/etc.; they are better than C-style loops which in turn are better than conditionals + gotos, but that doesn't make them good at expressing intent in many common cases.