Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

enumerator

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?

like image 613
Christoffer Lette Avatar asked Oct 13 '08 11:10

Christoffer Lette


2 Answers

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.

like image 168
Jon Skeet Avatar answered Sep 22 '22 02:09

Jon Skeet


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

The consumer of the code, can always stop enumerating (using break for example or other means). If your enumerator returns and infinite sequence, that doesn't mean the client of the enumerator is somehow forced to never break enumeration, actually you can't make an enumerator which is guaranteed to be fully enumerated by a client.

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

Yes, as long as you clearly specify in your documentation that the enumerator returns and infinite sequence and breaking of enumeration is the caller's responsibility, everything should be fine.

Returning infinite sequences isn't a bad idea, functional programing languages have done it for a long time now.

like image 20
Pop Catalin Avatar answered Sep 25 '22 02:09

Pop Catalin