On Wednesday, 5 February 2014 at 12:08:11 UTC, Jens Mueller wrote:
Jakob Ovrum wrote:
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();
>});
>
>Jens
Consuming 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.
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.
Jens
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();
}