foreach is a loop or iterator? Or can it be both?

Asked

Viewed 713 times

18

In a video tutorial the instructor stated not to fall for the nonsense of thinking that the foreach is a loop, and it was vehement that he was an iterator.

There are cases where we can go through the items of an array using foreach as a "compact for version".

That is, when we use foreach for arrays or matrices, in the background we are using it as a compact version of loop for. When we use it to iterate collections, it is in fact a TRUE iterator because "access" the methods of the Ienumerator

Is the statement correct? Can anyone add anything about it?

Follow example code:

//foreach com Arrays
    int[] array = new int[]{1, 2, 3, 4, 5, 6};
    foreach (int item in array) 
    {
      Console.WriteLine(item);
    }

However, the C# compiler generates C# code equivalent to the generated CIL:

//Código C# equivalente ao CIL gerado
    int[] tempArray;
    int[] array = new int[]{1, 2, 3, 4, 5, 6};
    tempArray = array;
     for (int counter = 0; (counter < tempArray.Length); counter++) {
       int item = tempArray[counter];
       Console.WriteLine(item);
    }

The code above was taken from the book: Essential C-6.0, 5th Edition [ Author Mark Michaelis ] page 582 inserir a descrição da imagem aqui

  • 4

    This excerpt from the book "Listing 14.6 demonstrates a simple foreach loop iterating over an array ..." is enlightening.

3 answers

22


In general video lessons are made by people who barely understand the language, let alone programming languages. I won’t talk about specific case, but always keep this in mind. There are even good things, usually in English and are paid, as the Pluralsight.

All that runs directly in repetition is a loop, or loop in English. So both are loops yes.

If the intention was to say foreach does not do the traditional process that is usually done in a for, is also wrong.

The foreach is a mechanism to iterate with a data collection. How this is done depends on a few factors. The most common way is to use an iterator provided by the collection, but it is possible to use the same algorithm as the for in cases such as the array and string. Although it does not exist, nothing prevents in the future having other mechanisms or other objects that iterate without a ready iterator.

Let’s look at the code using the two forms:

using static System.Console;
using System.Collections.Generic;
public class C {
    public static void Main() {
        int[] array = new int[]{1, 2, 3, 4, 5, 6};
        foreach (int item in array) WriteLine(item);
        var lista = new List<int>{1, 2, 3, 4, 5, 6};
        foreach (int item in lista) WriteLine(item);
        var texto = "123456";
        foreach (char item in texto) WriteLine(item);
    }
}

Behold working in the ideone. And in the .NET Fiddle. And see decompiled in Sharplab. Also put on the Github for future reference.

Of course, the way the decompiler will govern the source depends on its quality, but it is clear that in the case of array turns into something without iterator provided by it, just as string, and with a list a ready iterator is used, so it can rebuild itself foreach. But the foreach with iterator actually is equivalent to this code:

IEnumerator<int> enumerator = lista.GetEnumerator();
try {
    while (enumerator.MoveNext()) {
        int item = enumerator.Current;
        WriteLine(item);
    }
} finally {
    IDisposable disposable = enumerator as IDisposable;
    if (disposable != null) disposable.Dispose();
}

So it’s a loop also.

Note that even the for uses an iterator, but it’s a manual that the programmer controls as he wants.

See what it is iteration.

  • Thank you very much for the reply @bigown. I edited in the question itself the bibliographic reference in which the author cites the CIL question about the use of foreach for array. The instructor cited said that the array implements the "factory" Ienumerable which causes the foreach to directly access the "super-powers" of the Ienumerator. You can add something about this?

  • 2

    I can say that he does not know very well what he is talking about, the compiler does an optimization that disregards the IEnumerator and does not access anything directly, and goes from 0 to its size, as you would manually with a for, as has already been demonstrated.

  • 3

    @Eduardomoscatelli, here you can get a sense of how the compiler works with loops, in case what it will generate for (for, foreach and while)

7

As stated in @Maniero’s reply, foreach is a loop because it runs a block of code repeatedly, in a nonrecursive way, such as the while, for or do-while, or even goto in some scenarios.

I don’t know what the tutor wanted to explain, but if I were the tutor I would explain that the foreach is a simplified way to use a IEnumerable<T>.

As you can see IEnumerable<T> has only one method IEnumerator<T> GetEnumerator(). If the foreach did not exist would have to write a code similar to this to traverse the elements:

IEnumerable<string> values = new[]{"olá"};
var it = values.GetEnumerator();
while(it.MoveNext()){
    Console.WriteLine(it.Current);
}

The foreach then allows you to have a simpler code. In fact whenever you use the foreach It actually generates a code similar to the one I showed you.

But the story does not end here. If you pay attention you see that the IEnumerator<T> also implements the interface IDisposable. And in reality when you use the foreach the platform also generates code to call the Dispose.

In other words, there’s something missing from the code I showed you earlier:

IEnumerable<string> values = new[]{"olá"};
var it = values.GetEnumerator();
using(it){
    while(it.MoveNext()){
        Console.WriteLine(it.Current);
    }
}

Now you have a general idea of how foreach works. The code generated by .NET should not be very different from.

Note - The platform. NET is evolving and it is normal that they have found a way to generate more efficient code depending on the data structure being used. It seems that according to the book quoted by the questioner, they found a way to optimize the code generated to traverse any array, or even any IList

  • Thank you so much for the @Brunocosta reply, I really liked your comments. Only one question comes to me when you say foreach is a loop and also a simplified way to use a Ienumerable<T>. Loops to my mind make repetitions "irrational", and it seems to me that when the foreach has access to the Movenext of Ienumerator, it starts to act as iterator not? You have something to add about?

  • @Eduardo Moscatelli An iterator is any mechanism that traverses a sequence of data. As Voce suggested, this is the additional feature of an iterator relative to a loop. Not all loops are iterators. But all iterators need loops or recursiveness.

  • I sign at the bottom.

4

Hello, I found this discussion a little bit interesting, and just to complement what @Brunocosta and @Maniero said, note that the following code below also works normally:

IEnumerable<string> itens = new string[1] { "meu texto" };

for (IEnumerator<string> it = itens.GetEnumerator(); it.MoveNext();)
{
    Console.WriteLine(it.Current);
}

Note that here I also gave up the syntax sugar proposed by foreach using the for, being possible to iterate with a collection IEnumerable<string>.

Note: The above code is solely intended to discipline, in order to show that both foreach have the characteristics of a loop, as well as to iterate collections. I do not recommend using this approach, precisely because we have the own foreach to do so.

  • Thank you very much, guys, for all the answers. The instructor in response to my inquiry said that all arrays implement the Ienumerable interface and that he did not agree with me that foreach might be a loop as well. I still wonder if the use of foreach to iterate a simple array occurs with a fake of the "for" created by CIL or if it actually accesses all the "powers" of Ienumerator through Ienumerable that already comes factory in all arrays. Someone to light a flashlight in this dark tunnel? hahah

  • 1

    @Eduardomoscatelli as I said, he even has problems interpreting text. He doesn’t even know what a loop. Just understand that in CIL there is nothing for, it has lower level mechanism than a for which is already an abstraction. But there is no use of the IEnumerable in a loop of array, although this is an implementation detail and in theory no programmer needs to know it to program correctly, it is only useful to understand a little more than naive programmers.

  • The code problems of this answer is that it makes the memory leak and that a array is not compiled for something equivalent to this.

  • @bigown I know an array is not compiled for this, including know of memory leakage, but as the answer text itself says, it’s just an example of how for and foreach work iterating collections, reinforcing their thesis on loop, for obvious reasons it is clear that I do not recommend the use of this code, being only a theoretical approach on the subject.

  • 1

    The issue of loop is ok, it’s just that I thought I could get the impression that it’s this code that’s generated, made more clearly the alert, gets better.

  • 3

    @bigown adjusted response to better future understandings.

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.