views:

272

answers:

4

C# 2 and VB.Net 8 introduced a new feature called iterators, which were designed to make it easier to return enumerables and enumerators.

However, iterators are actually a limited form of coroutines, and can be used to do many useful things that have nothing to do with collections of objects.

What non-standard uses of iterators have you seen in real code?

+8  A: 

To start things off:

  • Jeffrey Richter wrote a powerful threading system called AsyncEnumerator using iterators. It's described in MSDN Magazine, parts one and two.
  • Iterators can also be used to wait for UI interaction within a method without blocking the UI thread, as I described here.
  • In a similar vein, I used iterators to create an IE-based web scraper, with scraping methods that return IEnumerators of WebActions which call back into the enumerator when ready. (Typically, when the document finishes loading).
    If people are interested, I can post it here.
SLaks
+6  A: 

I used them to write a system in ASP.NET for creating a series of linked page interactions. If you imagine a user's conversation with a website as a series of requests and responses, you can model an interaction as an IEnumerable. Conceptually, like this;

IEnumerable<PageResponse> SignupProcess(FormValues form)
{
   // signup starts with a welcome page, asking
   // the user to accept the license.
   yield return new WelcomePageResponse();

   // if they don't accept the terms, direct 
   // them to a 'thanks anyway' screen
   if (!form["userAcceptsTerms"])
   {
      yield return new ThanksForYourTimePageResponse();
      yield break;
   }

   // On the second page, we gather their email;
   yield new EmailCapturePage("");
   while(!IsValid(form["address"]))
   {
     // loop until we get a valid address.
     yield return new EmailCapturePage("The email address is incorrect. Please fix.");
   } 
}

You can store the iterator in session state, so that when the user returns to the site you just pull the iterator out, move the iterator onto the next page, and yield it back for rendering. Complex site interactions are coded in a single place.

Steve Cooper
(I fixed your `yield` syntax) I really like that idea. It would be even better with ASP.Net MVC, but it might take some trickery to set up.
SLaks
Thanks. I suspect you could rip out the standard routing stuff from MVC, but I think you're right -- it'd be a lot of work. I also have _no idea_ how I'd make it work with async AJAX calls...
Steve Cooper
Where would you put that between page requests? On a stateless, clustered server? I'm not sure that is all so wonderful, sorry.
Marc Gravell
No, you couldn't run it on a server farm. I mention it as an example of wacky stuff with itserators, not necessarily as a fully-developed web framework :)
Steve Cooper
@Marc: Many people (myself included) do not and will not run on server farms.
SLaks
@Marc Gravell - You have to admit this is pretty cool even if it won't work on some hardware configurations.
ChaosPandion
A: 

I wrote this function before I found out about the lazy yield operator. This recursively builds a massive iterator and returns it. It is not exactly efficient but I think it is clever.

static member generatePrimeNumbers max =    
    let rec generate number numberSequence =
        if number * number > max then numberSequence else
        let filteredNumbers = numberSequence |> Seq.filter (fun v -> v = number || v % number <> 0L)
        let newNumberSequence = seq { for i in filteredNumbers -> i }
        let newNumber = newNumberSequence |> Seq.find (fun x -> x > number)
        generate newNumber newNumberSequence                
    generate 2L (seq { for i in 2L..max -> i })
ChaosPandion
What language is that? F#?
SLaks
Yeah, the seq keyword is an alias for IEnumerable.
ChaosPandion
A: 

I used it to recursively iterate over the files contained in a folder, its subfolders and so on. For every file I had to perform a specific action. A recursive function with "yield return" statements was simple for everyone's else understanding.

lmsasu