digitalmars.D - std.algorithm missing for_each?
- Jens Mueller (25/25) Feb 05 2014 Dear lovely D community,
- bearophile (25/33) Feb 05 2014 Adding something like each() has being proposed, but so far no
- bearophile (7/11) Feb 05 2014 Possibly better:
- Idan Arye (26/37) Feb 05 2014 I is unclear from the syntax whether `(e)` is a the argument list
- Meta (3/5) Feb 05 2014 I implemented it, but the newsgroup reaction was somewhat opposed
- Jens Mueller (4/10) Feb 05 2014 Can you point me to that forum thread? I'd like to see the arguments
- Meta (2/16) Feb 05 2014 http://forum.dlang.org/thread/ovbjcmogezbvsxrwfcol@forum.dlang.org
- Andrei Alexandrescu (4/18) Feb 05 2014 Also relevant:
- Meta (4/28) Feb 05 2014 The major problem (i.e., syntactical) of for_each in C++ don't
- Jakob Ovrum (11/44) Feb 05 2014 Consuming an input range in the functional style should be done
- Jens Mueller (14/67) Feb 05 2014 Rephrasing your words to get a clear image for myself: You argue that
Dear lovely D community, recently I refactored some code into component style (see Component Programming in D by Walter http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321) It looks about like this someInputRange .filter!() .map!() Next I want to discard all elements but perform some last operation on each element. The problem is that map forces me to pass a function that returns. Of course I could return a fake value. But that doesn't look proper. Another option is to iterate using the foreach loop. Does not look better either, does it? This makes me believe that std.algorithm misses an algorithm. The for_each algorithm (see for_each in STL http://www.cplusplus.com/reference/algorithm/for_each/). To rephrase the problem more general (because maybe I'm just not seeing how to fit the pieces together): How do you perform some arbitrary operation on the elements of a range? myRange .each!((e) { e.someOperation(); }); Jens
Feb 05 2014
Jens Mueller:Another option is to iterate using the foreach loop. Does not look better either, does it? ... myRange .each!((e) { e.someOperation(); });Adding something like each() has being proposed, but so far no one has implemented it for Phobos. But the need of each() is not strong, there are more important functions to add, like a sum() (being implemented by Andrei), and more. Using foreach() is not bad, it shows clearly to the reader that the code is doing something imperative. So it breaks the style of the UFCS chains, but such breakage reflects the semantic breakage. And the syntax of the each() you have written is a little less readable than a foreach (unless the usage of jQuery and the like has trained your eyes to not see them). One good thing of each() is that it at the end of the chain, while you need to put foreach at its start. This is not handy and it's enough to ask for a each() in Phobos. To improve the syntax of each() and make similar imperative procedures look more like language constructs, some persons have suggested an alternative syntax sugar for functions that have a delegate as last argument: myRange .each { e.someOperation; }; Bye, bearophile
Feb 05 2014
myRange .each { e.someOperation; };Possibly better: myRange .each (e) { e.someOperation; }; Bye, bearophile
Feb 05 2014
On Wednesday, 5 February 2014 at 11:21:12 UTC, bearophile wrote:I is unclear from the syntax whether `(e)` is a the argument list and `{...}` is a block lambda or the property syntax is used and `(e) {...}` is a regular lambda. How about using the Ruby style of blocks: myRange .each do(e) { e.someOperation; }; This will also give a nice syntax when passing named functions: myRange.each do writeln; Alternatively, we can fuse the delegate definition with the higher order function's call syntax like this: myRange .each (auto e) { e.someOperation; }; Here, `(auto e)` *is* the argument list of `each`, but it's clear that `e` is not an argument passed to `each` because it uses the declaration syntax rather than being an expression. Actual arguments could be passed in the same list: forEachInRange(auto i, 0, 10) { ... } This, ofcourse, will require some special syntax for declaring the higher order function.myRange .each { e.someOperation; };Possibly better: myRange .each (e) { e.someOperation; }; Bye, bearophile
Feb 05 2014
On Wednesday, 5 February 2014 at 11:17:48 UTC, bearophile wrote:Adding something like each() has being proposed, but so far no one has implemented it for Phobos.I implemented it, but the newsgroup reaction was somewhat opposed to it.
Feb 05 2014
Meta wrote:On Wednesday, 5 February 2014 at 11:17:48 UTC, bearophile wrote:Can you point me to that forum thread? I'd like to see the arguments raised. JensAdding something like each() has being proposed, but so far no one has implemented it for Phobos.I implemented it, but the newsgroup reaction was somewhat opposed to it.
Feb 05 2014
On Wednesday, 5 February 2014 at 13:32:28 UTC, Jens Mueller wrote:Meta wrote:http://forum.dlang.org/thread/ovbjcmogezbvsxrwfcol forum.dlang.orgOn Wednesday, 5 February 2014 at 11:17:48 UTC, bearophile wrote:Can you point me to that forum thread? I'd like to see the arguments raised. JensAdding something like each() has being proposed, but so far no one has implemented it for Phobos.I implemented it, but the newsgroup reaction was somewhat opposed to it.
Feb 05 2014
On 2/5/14, 5:36 AM, Meta wrote:On Wednesday, 5 February 2014 at 13:32:28 UTC, Jens Mueller wrote:Also relevant: http://programmers.stackexchange.com/questions/170939/how-to-make-the-switch-to-c11 AndreiMeta wrote:http://forum.dlang.org/thread/ovbjcmogezbvsxrwfcol forum.dlang.orgOn Wednesday, 5 February 2014 at 11:17:48 UTC, bearophile wrote:Can you point me to that forum thread? I'd like to see the arguments raised. JensAdding something like each() has being proposed, but so far >no one has implemented it for Phobos.I implemented it, but the newsgroup reaction was somewhat opposed to it.
Feb 05 2014
On Wednesday, 5 February 2014 at 18:38:04 UTC, Andrei Alexandrescu wrote:On 2/5/14, 5:36 AM, Meta wrote:The major problem (i.e., syntactical) of for_each in C++ don't apply in D due to UFCS and how ranges are implemented.On Wednesday, 5 February 2014 at 13:32:28 UTC, Jens Mueller wrote:Also relevant: http://programmers.stackexchange.com/questions/170939/how-to-make-the-switch-to-c11 AndreiMeta wrote:http://forum.dlang.org/thread/ovbjcmogezbvsxrwfcol forum.dlang.orgOn Wednesday, 5 February 2014 at 11:17:48 UTC, bearophile wrote:Can you point me to that forum thread? I'd like to see the arguments raised. JensAdding something like each() has being proposed, but so farI implemented it, but the newsgroup reaction was somewhat opposed to it.no onehas implemented it for Phobos.
Feb 05 2014
On Wednesday, 5 February 2014 at 10:03:52 UTC, Jens Mueller wrote:Dear lovely D community, recently I refactored some code into component style (see Component Programming in D by Walter http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321) It looks about like this someInputRange .filter!() .map!() Next I want to discard all elements but perform some last operation on each element. The problem is that map forces me to pass a function that returns. Of course I could return a fake value. But that doesn't look proper. Another option is to iterate using the foreach loop. Does not look better either, does it? This makes me believe that std.algorithm misses an algorithm. The for_each algorithm (see for_each in STL http://www.cplusplus.com/reference/algorithm/for_each/). To rephrase the problem more general (because maybe I'm just not seeing how to fit the pieces together): How do you perform some arbitrary operation on the elements of a range? myRange .each!((e) { e.someOperation(); }); JensConsuming an input range in the functional style should be done by std.algorithm.copy (passing an output range) or by simply passing the input range to the consumer algorithm. Sometimes this isn't possible, which means reverting to foreach, i.e. a mix of functional and imperative style. This is the equivalent of STL's `for_each`. I think adding an `each` function to Phobos is problematic. It is syntax sugar for foreach, but with the downside of obfuscating what is essentially imperative code. IMO, imperative code should look like imperative code, which with foreach is by no means ugly.
Feb 05 2014
Jakob Ovrum wrote:On Wednesday, 5 February 2014 at 10:03:52 UTC, Jens Mueller wrote:Rephrasing your words to get a clear image for myself: You argue that foreach (e; someInputRange .filter!() .map!()) e.someOperation(); is not ugly and the way to go. And someInputRange .filter!() .map!() .each!(); is bad because it mixes two styles. JensDear lovely D community, recently I refactored some code into component style (see Component Programming in D by Walter http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321) It looks about like this someInputRange .filter!() .map!() Next I want to discard all elements but perform some last operation on each element. The problem is that map forces me to pass a function that returns. Of course I could return a fake value. But that doesn't look proper. Another option is to iterate using the foreach loop. Does not look better either, does it? This makes me believe that std.algorithm misses an algorithm. The for_each algorithm (see for_each in STL http://www.cplusplus.com/reference/algorithm/for_each/). To rephrase the problem more general (because maybe I'm just not seeing how to fit the pieces together): How do you perform some arbitrary operation on the elements of a range? myRange .each!((e) { e.someOperation(); }); JensConsuming an input range in the functional style should be done by std.algorithm.copy (passing an output range) or by simply passing the input range to the consumer algorithm. Sometimes this isn't possible, which means reverting to foreach, i.e. a mix of functional and imperative style. This is the equivalent of STL's `for_each`. I think adding an `each` function to Phobos is problematic. It is syntax sugar for foreach, but with the downside of obfuscating what is essentially imperative code. IMO, imperative code should look like imperative code, which with foreach is by no means ugly.
Feb 05 2014
On Wednesday, 5 February 2014 at 12:08:11 UTC, Jens Mueller wrote:Jakob Ovrum wrote:Your `foreach` is ugly because you need to look closely to see the boundary between the functional chain and the iterative execution. In this case, adding a block makes things much more elegant: foreach (e; someInputRange .filter!() .map!()) { e.someOperation(); }On Wednesday, 5 February 2014 at 10:03:52 UTC, Jens Mueller wrote:Rephrasing your words to get a clear image for myself: You argue that foreach (e; someInputRange .filter!() .map!()) e.someOperation(); is not ugly and the way to go. And someInputRange .filter!() .map!() .each!(); is bad because it mixes two styles. JensDear lovely D community, recently I refactored some code into component style (see Component Programming in D by Walter http://www.drdobbs.com/architecture-and-design/component-programming-in-d/240008321) It looks about like this someInputRange .filter!() .map!() Next I want to discard all elements but perform some last operation on each element. The problem is that map forces me to pass a function that returns. Of course I could return a fake value. But that doesn't look proper. Another option is to iterate using the foreach loop. Does not look better either, does it? This makes me believe that std.algorithm misses an algorithm. The for_each algorithm (see for_each in STL http://www.cplusplus.com/reference/algorithm/for_each/). To rephrase the problem more general (because maybe I'm just not seeing how to fit the pieces together): How do you perform some arbitrary operation on the elements of a range? myRange .each!((e) { e.someOperation(); }); JensConsuming an input range in the functional style should be done by std.algorithm.copy (passing an output range) or by simply passing the input range to the consumer algorithm. Sometimes this isn't possible, which means reverting to foreach, i.e. a mix of functional and imperative style. This is the equivalent of STL's `for_each`. I think adding an `each` function to Phobos is problematic. It is syntax sugar for foreach, but with the downside of obfuscating what is essentially imperative code. IMO, imperative code should look like imperative code, which with foreach is by no means ugly.
Feb 05 2014
On Wednesday, 5 February 2014 at 12:18:15 UTC, Idan Arye wrote:Your `foreach` is ugly because you need to look closely to see the boundary between the functional chain and the iterative execution. In this case, adding a block makes things much more elegant: foreach (e; someInputRange .filter!() .map!()) { e.someOperation(); }I think that's a bit of an exaggeration. A hypothetical each() function would almost always be at the end of a UFCS chain, making it clear that it's iterating and consuming the result. This is no worse than putting .array at the end of a chain to force evaluation (and is actually much clearer about intent).
Feb 05 2014