BrandGhost

What the HECK are Iterators in .NET C#

Enumerables and iterators are a confusing topic for many people even if they aren't new to C#. In this video we'll look at what an iterator is in C# and what separates it from a normal method that returns IEnumerable. This video is introductory level and will allow you to follow up with a more advanced video, like this one: https://youtu.be/3a_hg8KE-aQ Want the source for this video? Check it out here: https://github.com/ncosentino/DevLeader/tree/master/AllAboutEnumerables/AllAboutEnumerables.I...
View Transcript
All right, you've heard about innumerabs in C, but what the heck are iterators? Before I go into answering that, I would love to hear from you in the comments if you think that you can explain what a C iterator is to other C developers. Okay, so innumerabs and collections are topics that we always keep visiting in C because they're very common things and iterators might be something that you've encountered, but you're not actually sure exactly what they are. So, I'm going to be diving into some code examples, walking us through how we can create iterators and what they are. So, it's still going to be a very beginner focused topic. We're going to dive into more details about iterators in follow-up videos. But to get our feet wet, we're going to look at the very basics. And before I switch over to code, if you could do me a favor, like this video, subscribe to the channel if you find this content valuable, and of course, if you know other C developers that are kind of working their way through iterators, it would be great to share this video with them as well so that they can learn. All right, let's jump over to the code. Okay, great. So, what I have on my screen here is going to be available in the public GitHub repository, and I'll have a link for that in the description. So you can go check that out and play around with this code so that you know I'm not just making up what I'm showing you on screen and the results we're going to see. You can go try it for yourself. Cool. Okay. So at the very top of my screen, you can see that I've declared an integer array with the numbers 1 through 5. Now what we can see at the very top here is a function just called simple innumerable. And all that it does is return that data set. But we can see that the return type is I innumerable. Nothing too fancy there. So what's an iterator? Well, iterators in C use a special keyword and we can see that if we look at the method that spans from line 10 to 17 and that special keyword is called yield. So when we look at the structure of this method, we can also see that it returns an innumerable of ins. So I innumerable is also going to be required for an iterator. But what's different about this is that we're going to do a loop of some kind over our data set and then we're going to yield back each item individually. This is in contrast to the method above where we look at line six that just returns the whole result set. So let's go run this example and we can see that what we're going to do is just call a for each loop over this simple iterator. So let me go ahead and press F5 on my keyboard. I'll zoom in for us and we can see that it is really simple, right? So we call for each and the simple iterator. You can see that that's printing here on line 19. And then what we're going to do right after that is for each item that comes back from that iterator, we're going to write the number to the console. So at this point, you might be going, "Okay, great. But wouldn't the first method do that anyway? What the heck is the point of having an iterator with this extra code with the for each and the yield return? Why not just do the original thing? It's even fewer lines of code." Great question. So let's dig a little bit deeper. So you can see that I have these prompting questions in the code. Okay, great. So I've uncommented this block of code and what I want to show you is that using an iterator, this actually affords us the opportunity to basically insert extra code throughout the iteration of the collection that we're looking at. So yes, this example is a little bit contrived because you probably would not be trying to write to the console this many times as you're stepping through a collection. But the point that I want to demonstrate in this example is that you can actually sort of hook into the code where you would like. And uh the prints here, the console write lines, we're just going to demonstrate where you have that ability. If you'll notice on lines 44 through 47 that I have highlighted in the bottom here, this is still structured the exact same as the method that was above. We're just going to go ahead and print the numbers back to the console. You can see that I left the original example in at the top. So I'm just going to scroll that right out of view for us. And what's on my console right now is representing the code that we actually have. We can see for each and console writing iterator. That's this line 43. Now what's really interesting is instead of just getting the numbers printed out, you can see that we got to print a line at the very beginning of this iterator. And then we can actually see that before we yield return every item, we can see that there's a before yield return, a before yield return, a before yield return, so on and so forth. And we also have one for after the yield return, which you can see showing up in the console as well. So when you just return the collection that I showed you in the first example, you actually don't have this opportunity with an iterator. we can actually start to do a little bit more customization in the method. This isn't the primary reason that you might want to use an iterator. I'm just trying to demonstrate to you that you have these opportunities when you are using iterators. What else is interesting about iterators? Well, I'm going to demonstrate a property here about iterators that's really unique that you might not even been aware of. So, what we're going to do is check out these methods. This one is structured to be not an iterator and it's not an iterator because it does not have a yield return inside of it. That's one of the key requirements. Yes, it is an I innumerable but it does not have any yield return inside. Now inversely we have this one that is an iterator and you can see that the only structural difference is this part where we don't return the entire data set. we do a yield return of each item. Therefore, it makes this one an actual iterator. Okay, great. What's going to happen when we run this? Great question. So, what we're going to do by looking at this code, we're just going to literally assign the result of that function to a variable. And we're going to do that for the noniterator. And we're going to do that for the iterator. Let's see what happens. All right. So this is the output of the last example and we can see here that when we're calling the function that sleeps for 5 seconds not the iterator we can see that we have a time stamp at 37 and the next time stamp when it's finished is 5 seconds later. So the noniterator if I scroll to the code the noniterator literally slept for that full 5 seconds because that's what the code says it's going to do. The iterator on the other hand actually finished instantly. It also has a thread sleep for 5 seconds. So how is it possible that the iterator itself did not actually go sleep for 5 seconds? That's because iterators have a property about them that is that they are lazy. And what I mean by that is that this line here on line 74 is actually not more like a collection than it is like a function pointer. So that means that result B being assigned the value of iterator that sleeps for 5 seconds first is not actually making a collection. What it is actually doing is taking a variable and pointing it at the function that is the iterator. It is quite literally just assigning a function pointer to a variable. And this is why it happens extremely fast. So that means that we have not actually performed the iteration at this point in time. All right, cool. So, I'm going to leave this video on a little bit of a cliffhanger because I do have a follow-up video that's going to demonstrate in more detail about that lazy behavior we see with iterators. So, you can go ahead and watch that right after this one. So, before moving on, I would love to hear from you in the comments if you have any more questions about how iterators work, any more thoughts about comparisons between collections and iterators, or any curiosities that still aren't totally clear. So, thanks so much for watching. If you like this video, please give it a thumbs up. Subscribe to the channel because it helps me know that you enjoy content like this. And of course, if you know other C developers that would benefit from this, please share so they can learn as well. Thanks, and we'll see you next time.

Frequently Asked Questions

What is the main difference between using an iterator and returning a collection directly?

The main difference is that an iterator allows you to yield items one at a time, which gives you the opportunity to insert additional code during the iteration process. This means you can perform actions before and after yielding each item, whereas returning a collection directly just gives you the entire set of items at once.

Why does the iterator finish instantly even if it contains a sleep command?

The iterator finishes instantly because it is lazy. When you assign the iterator to a variable, you're not executing the function; you're just pointing to it. The actual iteration happens only when you start to enumerate over it, which is why it doesn't sleep for the full duration right away.

Will there be more videos explaining iterators in detail?

Yes, I have a follow-up video planned that will dive deeper into the lazy behavior of iterators and explore more advanced concepts. So stay tuned for that!

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload