11

Possible Duplicate:
Why is there not a ForEach extension method on the IEnumerable interface?

Hello,

My question is why Foreach extension method is defined on List rather than IEnumreable. i have read Eric Lippert's article but the point is, if it is so bad to have such method than why is it there for List?

The Chairman
  • 7,087
  • 2
  • 36
  • 44
Muhammad Adeel Zahid
  • 17,474
  • 14
  • 90
  • 155
  • Which ForEach are you talking about? `List<>` doesn't have one. – H H Apr 18 '11 at 15:13
  • 2
    It sure does. http://msdn.microsoft.com/en-us/library/bwabdf9z.aspx Personally I disagree with the basic rationale from that article, that it doesn't improve readability. That's the primary benefit, and it's a useful one entirely for that reason. Creating a chainable extension method for `IEnumerable` is trivial. – Jamie Treworgy Apr 18 '11 at 15:17
  • Maybe you can read Eric's answer to the very first comment on his article for an answer to your question. – Jb Evain Apr 18 '11 at 15:22
  • I like his answer: the one hand doesn't know what the other is doing, basically. – Jamie Treworgy Apr 18 '11 at 15:27
  • 1
    They were so busy wondering if they could, they never stopped to think if they should *slams fist on table* (thank you, Jurassic Park) – Jeff Yates Apr 18 '11 at 15:40
  • @jamietre yes its trivial but point is does microsoft provide any reason for implemnting on List and not in Linq for IEnumerable. i m convinced on Mark's answer that Linq should not produce side effects – Muhammad Adeel Zahid Apr 18 '11 at 15:49
  • I'm fine with his answer, as far as just having an answer. But what he does not do is provide any reason for the basic premise, that Linq should not produce side effects. – Jamie Treworgy Apr 18 '11 at 15:54
  • @jamiet: You're right, Intellisense failure on my end. – H H Apr 18 '11 at 16:54
  • @Henk probably they want Linq to produce same result every time it is executed on same enumeration this is what foreach voilates – Muhammad Adeel Zahid Apr 18 '11 at 17:33

4 Answers4

13

List<T>.ForEach() isn't an extension method. It's just a method on List<T>.

One of the main reasons that it isn't available in LINQ (i.e., Enumerable) is that LINQ queries are supposed to be free of side-effects (so you can, e.g., execute a query multiple times and get the same results without changing them), which makes them very composable. All the LINQ operations that accept delegates are for Func; none of them accept an Action delegate.

Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
  • Can you post an example of side effect, that will change the content of list within the foreach that can not be or is not possible in case of IEnumerable? To me it feels that ForEach is just an enumeration over IEnumerable of list. – Akash Kava Apr 18 '11 at 18:49
  • 1
    An example would be `list.ForEach(x=>list.Remove(x)) `.`List.ForEach()` doesn't use the `IEnumerable` interface—the method directly indexes an array. An exception is thrown if a collection is modified while iterating it with an enumerator. – Mark Cidade Apr 18 '11 at 19:01
  • Well it's a bug and half implemented feature, nowhere MSDN displays that ForEach was specially added to enumerate modified collection. See my answer. – Akash Kava Apr 19 '11 at 03:03
  • I have posted bug at here as well, https://connect.microsoft.com/VisualStudio/feedback/details/662882/list-foreach-allows-enumeration-over-modified-version-of-list – Akash Kava Apr 19 '11 at 03:06
6

This was a bug I had posted at Microsoft Connect Website, Microsoft already fixed it in upcoming .NET Edition as mentioned here in the following link.

List.ForEach allows enumeration over modified version of List

This probably isnt directly related to answer but its pretty funny of what I have just found out.

ForEach, delete (works)

List<int> list = new List<int>(){ 1, 2, 3, 4, 5, 6};

list.ForEach(x => {
    Console.WriteLine(x);
    list.Remove(x);
});

foreach, delete (crashes)

// throws exception
foreach (var x in list)
{
    Console.WriteLine(x);
    list.Remove(x);
}

ForEach, insert (...)

// goes in infinite loop...
list.ForEach(x => {
    list.Add(1);
});

foreach, insert (crashes)

// throws exception
foreach (var x in list)
{
    Console.WriteLine(x);
    list.Add(x);
}

So anyone who is talking here about mutability or different confusing layers etc, I think it is completely half implemented feature by Visual Team because enumeration will always cause problems if the collection is modified.

Despite of arguments, I still see a no reason that ForEach should allow modifications, it is purely used for enumeration and it makes no difference whether its foreach(var item in x) syntax or x.ForEach(x=>{}) syntax.

I disagree with Eric, I just see it simply that BCL team has implemented this feature on IEnumerable as well as list.ForEach is faulty.

"Why" is completely subjective,for example, Silverlight has added complex hashing algorithms and left MD5 behind where else everywhere else we use MD5 so widely. Its more of how much anything is in demand and who is the one who chooses whether to include it or not in framework.

There is no logical or philosophical reason at all for not having ForEach in IEnumerable. There are many such missing points which I think .NET will improve over time.

Akash Kava
  • 39,066
  • 20
  • 121
  • 167
  • 1
    +1 nice illustration of the way enumeration should be used – Muhammad Adeel Zahid Apr 18 '11 at 17:31
  • You're talking about modifications in terms of additions or removal to a list, which (sensibly) `foreach` doesn't allow. I don't think the List implementation should, either -- so it must be accessing by index from the top down for its iteration. But there are plenty of reasons why you might want to iterate through a list and cause side effects that are not destructive to the list itself, like change properties of members, or use information from the list to do something unrelated. – Jamie Treworgy Apr 18 '11 at 18:26
  • Change properties of items has nothing to do with list's mutability, please list a side effect, that should effect a list and enumerate at the same time that is not possible with IEnumerable – Akash Kava Apr 18 '11 at 18:46
1

What it comes down to is mutating state using LINQ should be avoided and not encouraged, LINQ's focus is on querying and transforming data, but not in place mutation - you lose many of the benefits of LINQs functional approach (i.e. no side effects, same input produces same output) if you do mutate state.

There is no benefit of Linq offering a ForEach() extension method over a normal foreach loop other than that it would aid you in mutating state - hence its not implemented (that's at least my take on it, take it with a grain of salt).

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
0

The 'why' is outside of my scope; I didn't make C#. However, it makes sense, as it will enumerate over your collection fully whereas most LINQ operators are lazily evaluated.

Tejs
  • 40,736
  • 10
  • 68
  • 86