There are two different types of iterator supported by C#, as mentioned below.
- External iterator
- Internal iterator
External iterator
A statement in which we need to specify each single step to complete the task is called an External Iterator in C#. Consider the below code snippet.
- List<string> cities = new List<string> { "Shimogga", "Sorab", "India" };
- for (int i = 0; i < cities.Count; i++)
- {
- Console.WriteLine(cities[i]);
- }
This is a very simple code. We already have been using this kind of codebase in our day to day application. We are just iterating over elements (string type) of a list collection. It might be others like a dictionary, array, hash table or custom collection but it contains so many moving parts. Some developers might argue that this is a very old way to iterate over a collection. They could be writing the same codebase in the following ways.
- foreach (var city in cities)
- {
- Console.WriteLine(city);
- }
Despite the above and prior one, the code produces the same output but the above one is much better than the prior one because the former one contains more moving parts. But here, an even more important thing is that there are semantical differences between for and foreach construct, for which we must be very thoughtful. That difference is "mutability".
- List<string> cities = new List<string> { "Shimogga", "Sorab", "India"};
- for (int i = 0; i < cities.Count; i++)
- {
- Console.WriteLine(cities[i]);
- i = 44;
- }
The above codebase only prints the first value from the collection because variable i is mutable (reinitialize its value) and it affects the state of the iterator. This one is the very big design flaw in the loop construct itself because it should not be mutable if it was iterating the index. In contrast, look at the below code.
- foreach (var city in cities)
- {
- Console.WriteLine(city);
- city = "Nadiad";
- }
Here, variable(city) is immutable, which means we cannot change the value of city variable. If we try, then the compiler become unhappy and gives above compile-time error message.
In both the above (for and foreach) code, we need to specify what to do and how to do it; this kind of programming style is known as the imperative style of programming.
Internal iterator
An expression is more concise and expressive. Let’s look at the below example
- List<string> cities = new List<string> { "Shimogga", "Sorab", "India"};
- cities.ForEach(city => Console.Write(city));
Here, the foreach function is a higher-order function, this means if a function takes one or more functions as arguments it is called high-order function (functional form/ functor). In the above code snippet ForEach function contains anonymous function(city=>Console.Write(city). It produces the same result as a prior external iterator (for and foreach). But this code snippet is declarative in nature. Declarative means we only need to specify what we want to do with each element, rather than how it does it.
In contrast to the external iterator where we must specify every minute detail like starting value, exit condition and so on, here we are giving up control of certain parts of our code to the underlying library (Base class library). So, we better focus on other important parts of our business logic rather than the thing we don’t need to care about. It also relieves us from many duties as a programmer.
One more important point about internal iterator is it supports polymorphism (Dynamic binding). The dot(.) before ForEach function is a polymorphic which means it says just go ahead and call me and I will tell you what I do but it does not reveal its how I do it. At runtime, it will work out how to do it based on the context of the Object it is working with. So, we get a little bit of flexibility through internal iterator in our code compared to an external iterator. Both for/foreach construct are the examples of static binding. So, such kind of programming style is called a declarative style of programming.
Conclusion
To summarize, whenever you need to do a lot of manual loops through the data structure, wait for a minute and start thinking about the internal iterator. Because C# language has the power but the biggest problem is our mindset. As a C# developer, our mind is wired with for/foreach loop construct for a long time, only because we are familiar with it, not because it provides a better way of programming. We just need to re-tune our mindset.
Then our code will express our ideas in nicer way. We only need to frame sets of functions together like,
- List<string> cities = new List<string> {"Shimogga", "Sorab", "India"};
- var query = cities.Where(n => n.Contains("V"))
- .OrderBy(n => n.Length)
- .Select(n => n.ToUpper());