The implementation of iterators in C# and its consequences (part 4)


You can breathe a sigh of relief. Our long national nightmare is over: this is the end of CLR Week 2008. We wind down with a look back at iterators.

Michael Entin points out that you can use C# iterators to make asynchronous code easier to write. You can use C# iterators for more than simply iterating.

The automatic conversion of straight line code into a state machine is handy when you want an easy way to write, well, a state machine. It’s one of those things that’s blindingly obvious once you look at it the right way.

The transformation that the yield return statement induces on your function turns it from a boring function into an implicit state machine: When you execute a yield return, execution of your function is suspended until somebody asks your iterator the next item, at which point execution resumes at the statement after the yield return. This is exactly what you want when breaking a synchronous function into asynchronous pieces: Each time you would normally block on an operation, you instead perform a yield return, and when the operation completes, you call the MoveNext method, which resumes execution of the function until the next time it needs to wait for something and performs a yield return.

It’s so simple it’s magic.

Additional iterator-related reading:

Comments (28)
  1. AndyB says:

    Something I think we can all agree on: Pingbacks suck.

  2. Nathan_works says:

    Now this adds something much more interesting to why we’d use an iterator discussion from earlier. I like the state machine idea.. Though I don’t know if I could apply it regularly in my work (nor iterators for that matter, which is why I didn’t grasp their use easily..)

  3. Josh says:

    All I want to know is what is up with the Chinese and their funny wallpaper…

  4. John says:

    Maybe somebody wrote a pingback iterator in C# and forgot to include an exit condition.

  5. Programmerman says:

    I already miss CLR week.  I look forward to next time.

  6. EricLippert says:

    A plea from the compiler team:

    Though it is assuredly the case that you CAN use iterators to implement state machines, poor-mans coroutines, and so on, I wish people would not do so.

    Please use tools for the purposes for which they were intended. If you want to write state machines, write yourself a library that is designed specifically to solve that general problem and then use it.  

    Using tools for purposes other than what they were intended for is "clever", and clever is bad; clever is hard for maintenance programemrs to understand, clever is hard to extend, clever is hard to reason about, clever makes people think "out of the box"; there’s good stuff in that box.

  7. fff says:

    Dear Americans! I write to you from Russia, because of bad knowledge of English I write through the electronic dictionary. Your Government deceives you, there are no forces already to look at it. Open at last eyes! Not Russia has attacked South Ossetia! Georgia has begun on August, 8th bombardment of Tskhinvali in the morning! Was lost more than 2 thousand civilians!!!!! The Georgian military men shot at the Russian peacemakers!!!! President of Georgia is a project of your government, created against Russia!!!! The instructions of the beginning of military operations have given the Government of the USA!!! If you really wish to know the truth, I urge you to take English – the Russian dictionary and to look the information on the Russian sites with news! Do not allow to your government to launch new war!!!! Consequences can be catastrophic!!!! We do not want war!!!!!!!! If to arise questions, write to me voron_sergey@mail.ru

  8. fffff says:

    Dear Russians, I write to you from America. Stay on topic.

  9. Daniel Colascione says:

    Eric, at least in Python, iterators come in handy for all sorts of tasks other than iterating over containers, and using them doesn’t lead to maintainability problems. What’s the problem if the feature works as intended?

  10. Mark Sowul says:

    Eric’s point is that cleverness leads to maintainability problems.  See also: just about every post on this blog explaining why something is strange in Win32.

  11. Moderation Required says:

    Our national nightmare may be over. The nightmare of pingback spam and off-topic postings is just beginning.

  12. JamesNT says:

    Lord Chen,

    Thank you, sir, for the excellent series on Iterators in C#.  This will actually help me solve some problems.

    I must say, though, that I will consider my life complete if you ever make a blog series using Visual Basic as the language.

    JamesNT

  13. ton says:

    Raymond you really must start doing more .NET  articles. Your technical insights are some of the better ones I’ve read. The fact is most developers don’t work anymore with Application Binary interfaces and assembly oops I mean

    Win 32 and C. Oh well if you’re only interested in history do the best history you can… :-)

  14. Worf says:

    @Eric: unfortunately, Raymond has already posted several million examples of people doing just that here, except in Win32. Your attempt at stopping developers will fail, unfortunately, and you’ll have compiler legacy patches that’ll rival Raymond and the Shell team :-). Welcome to the club.

  15. Alan says:

    Raymond, please do post more .NET articles. These were a joy to read and who knows how much more treasures you may have up your sleeve. You could even have a C# Month next time rather than just a CLR Week ;)

  16. Merus says:

    Thank you for the .Net discussion, Eric. Ignore the haters.

  17. This does look ingenious, at first.

    However, typically if your design leads you to think "state machine", the state diagram you have in mind will not be one that corresponds to the control flow of a structured procedure. For example, if the state diagram happens to contain a multiple-entry loop — not unusual for protocol state machines — it cannot be coded with structured control primitives at all.

    Trying to shoehorn your intended state machine into an iterator body is likely to lead you to either indiscriminate use of goto, or to explicit state variables that interact with with the apparent control-flow structure. In either case you’ll be better off coding the state machine honestly and explicitly.

    The real trap is if the state machine initially is nice enough to be coded as an iterator body, but later in the lifetime of the application grows warts for some reason. If the rest of the application is coded to view the state machine as if it was an iterator, you’re going to end up with a hard-to-understand design for no good reason.

    So if you do use the iterator trick, at the very least encapsulate it with a class such that its iterator-ness is not visible from the outside.

  18. divil5000@hotmail.com says:

    I wish there were more .net content on here. Whether it’s a CLR month, or (preferably) more than one CLR week per year.

  19. Michael J says:

    Pardon my ignorance as a humble C++ hacker, with approximately zero C# experience, but the C# iterator code looks like pure spaghetti!

    I’ve never heard of “yield return”, but can guess what it does from the context.  As a language construct, it seems like a recipe for trouble.

    The “case 0: goto resume$0;” construct causes flashing red lights in my head.  Jumping into a for loop seems beyond scary.

    I remember code like this in the Fortran IV days and with old versions of BASIC (before BASIC morphed into a variant of Pascal).  I also remember the long hours trying to unravel the intent of an old programmer who created the code.

    That is why we adopted “Structured Coding” and other such niceties.

    Now I’m not suggesting that the designers of C# were fools — I’m sure they had some rationale for this stuff, but from my humble vantage I am completely unable to see it.

    Michael J

    [If you look at the code the C++ compiler generates for exceptions, that looks like spaghetti too. (A “goto” into the middle of another function!?) Does that mean exceptions violate the principles of structured programming? Heck, if you look at the implementation of “for” it’s full of goto’s too! -Raymond]
  20. Anon (Writing on topic from Great Britain) says:

    @ Eric Lippert

    I’m really glad you said that. I’ve done a fair bit in VHDL, where the "synchronous state machine" is bread and butter.

    This stuff with iterators makes me nervous. In VHDL there are some "little things" which are extremely useful, but if you’re lax you get a nightmare. Do do that with whole machines seems scary.

    IME State machines that are explicit are good. By the time you have the pipeline involved, the last thing you want doubts about is what exactly the machine is doing, you’re much more worried about when it’s doing it.

    Coming from the position of a very conservative C/C++ perspective, I was reading the article of Stuart Leeks and thinking that these people doing C# are just violating all the general rules of systematic thinking and it’s seen as acceptable.

    To hear that the compiler team frown upon this gives me great confidence that the world is not going mad, and calling good sense bad.

  21. Erzengel says:

    divil said "more than one CLR week per year"

    I totally agree with this. As much as I like C++/Win32 and use it, I also write a lot of tools in C#. Raymond has great insight into both of these arenas.

    Michael J: You should see some of the stuff I see and have to do in C++.

    The thing that makes it not scary is that you don’t actually have to do that. With yield return, everything is abstracted away. Similarly to how the actual implementation of virtual functions might be a bit scary (a pointer to a table with pointers to functions. With a lot of other goop necessary for the variations on polymorphism such as multiple bases, deadly diamonds, etc), but it isn’t for us C++ users because the compiler does all the work.

  22. Miral says:

    I wish it was a .NET fortnight.  Or month, even :)  Or, yeah, more than one week per year.  This is all fascinating stuff.

    Encore!

  23. My latest in a series of the weekly, or more often, summary of interesting links I come across related to Visual Studio. Greg Duncan posted a link to the release announcement for Task Board for Team System Beta 2 . Raymond Chen discussed the implementation

  24. Mark Sowul says:

    +1 to ignoring C# haters and more frequent .NET content.

  25. JamesCurran says:

    Hmm… natural now the CLR week is over, it finally occurs to me that this would have been the perfect time pose a question that has puzzled me for some time:

    In .Net languages, reference types are stored in one place in memory, while value type are stored in another.  These places are generally referred to, respectively, as "The Heap" and "The Stack", mainly because,  there closest analogs back in C coding of the 1980’s were implemented using, respectively, a heap data structure, and a stack data structure.

    So, my question is, In the current CLR implementation, is the Heap still a heap? and is the Stack still a stack?

  26. peterchen says:

    Like anythging great, .NET week was good and to short.

    > In the current CLR implementation, is the Heap still a heap? and is the Stack still a stack?

    I don’t know implementation details, but as I understand yes.

    The heap has evovled – objects are relocatable and garbage collected and kept in different pools depending on size and age, but in the sense of "a heap of available memory from which dynamic memory allocations are taken", yes.

    IL itself is stack-based, so I guess that’s where the value type are, too.

  27. EricLippert says:

    The idea that "value types are on the stack" is a myth.  Value types are frequently not on "the stack" — when they are fields of reference types, for example, or locals hoisted into a closure by an iterator or anonymous function.

    But even given that, "the stack" and "the heap" are implementation details. The CLR gives you a memory model where you do not have to care about how the underlying implementation is managing storage.

    And besides, the original point of "the stack" vs "the heap" was that stack was cheap, heap was expensive. Anders jokes sometimes that "the heap is the new stack", and though it’s a joke, it’s also serious.  Heap allocation in the CLR is pretty cheap and the cost of collection is also pretty cheap when amortized over the runtime of the program.

    So don’t worry; love the heap.

  28. The Old New Thing : The implementation of iterators in C# and its consequences (part 3) Notes from a

Comments are closed.