Search code examples
c#enumerator

How do you design an enumerator that returns (theoretically) an infinite amount of items?


I'm writing code that looks similar to this:

public IEnumerable<T> Unfold<T>(this T seed)
{
    while (true)
    {
        yield return [next (T)object in custom sequence];
    }
}

Obviously, this method is never going to return. (The C# compiler silently allows this, while R# gives me the warning "Function never returns".)

Generally speaking, is it bad design to provide an enumerator that returns an infinite number of items, without supplying a way to stop enumerating?

Are there any special considerations for this scenario? Mem? Perf? Other gotchas?

If we always supply an exit condition, which are the options? E.g:

  • an object of type T that represents the inclusive or exclusive boundary
  • a Predicate<T> continue (as TakeWhile does)
  • a count (as Take does)
  • ...

Should we rely on users calling Take(...) / TakeWhile(...) after Unfold(...)? (Maybe the preferred option, since it leverages existing Linq knowledge.)

Would you answer this question differently if the code was going to be published in a public API, either as-is (generic) or as a specific implementation of this pattern?


Solution

  • So long as you document very clearly that the method will never finish iterating (the method itself returns very quickly, of course) then I think it's fine. Indeed, it can make some algorithms much neater. I don't believe there are any significant memory/perf implications - although if you refer to an "expensive" object within your iterator, that reference will be captured.

    There are always ways of abusing APIs: so long as your docs are clear, I think it's fine.