ardalis / ardalis/Ardalis.Extensions
Make ForEach return an Iterator, like `Tap` in other languages
- Dominant language
- C#
- Stars
- 162
- Forks
- 37
- PR merge metrics
- No merged PRs in 30d
Description
At the moment, our implementation of `ForEach` can only be used as the only or last step in a LINQ operations pipeline as it forces the execution of the chain of operations and returns void.
Just because `ForEach` allows us to perform side effects doesn't mean that it needs to take us out of the Iterator pipeline. I'm thinking of the `tap` operator that exists in many other languages and libraries as an example of allowing the "streaming" to continue.
https://rxjs.dev/api/operators/tap
https://hexdocs.pm/elixir/main/Kernel.html#tap/2
This would allow for things like this:
```cs
var blueWhalesWeight = whales
.Where(w => w.Color == "blue")
.ForEach(w => Console.WriteLine(w.Name))
.Select(w => w.Weight)
.ToList();
```
This would also mean that it is no longer possible to just do:
```cs
whales
.Select(w.Color == "blue")
.ForEach(w => Console.WriteLine(w.Name));
```
I guess at the end of the day it depends on our philosophy regarding Iterators. There is a reason why many languages choose to not implement a ForEach on their Iterator and that is because it doesn't fit very well with the abstraction. Iterators tend to encourage a more "functional" approach by creating a pipeline of operations where data comes in on one end, goes through a set of pure functions, and comes out at the other end transformed. The ForEach kind of breaks that abstraction in two ways:
1) the very intent of the method is to make side effects
2) it doesn't return anything
Languages have compromised with this by introducing the `tap` operation, which allows for side effects, but keeps the flow of data going.
So, I guess I'm proposing that we either 1) make `ForEach` into a `Tap` or, if we prefer to leave `ForEach` the way it is, that we introduce a `Tap` extension method.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by locating the existing ForEach extension and reviewing its return type and usages. Resolve whether the project should change ForEach to return the iterator or add a separate Tap method; done means the chosen API supports the shown chained pipeline while preserving the intended behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100