-3

Edit: Apparently off topic...moving to Programmers.StackExchange.com.

This isn't a practical problem, it's more of a riddle.

Problem

I'm curious to know if there's a way to implement something equivalent to the following, but without using yield:

IEnumerable<T> Infinite<T>()
{
    while (true) { yield return default(T); }
}

Rules

  1. You can't use the yield keyword
  2. Use only C# itself directly - no IL code, no constructing dynamic assemblies etc.
  3. You can only use the basic .NET lib (only mscorlib.dll, System.Core.dll? not sure what else to include). However if you find a solution with some of the other .NET assemblies (WPF?!), I'm also interested.
  4. Don't implement IEnumerable or IEnumerator.

Notes

The closest I've come yet:

IEnumerable<int> infinite = null;
infinite = new int[1].SelectMany(x => new int[1].Concat(infinite));

This is "correct" but hits a StackOverflowException after 14399 iterations through the enumerable (not quite infinite).

I'm thinking there might be no way to do this due to the CLR's lack of tail recursion optimization. A proof would be nice :)

Community
  • 1
  • 1
sinelaw
  • 16,205
  • 3
  • 49
  • 80
  • Why? yield is a perfectly good option for this, why would you want to tie your hands like that? – Sam Axe Nov 07 '13 at 03:30
  • Second, as there is a perfectly valid way to accomplish the task, namely `yield`. This question does not belong on SO. You might try Programmers.SE or CodeReview.SE. – Sam Axe Nov 07 '13 at 03:31
  • @Dan-o: I bet it's one of that silly work interviewers who ask weird questions - asked sinelaw such a question on an interview, so now he is curious of what he would answer :-) – zerkms Nov 07 '13 at 03:32
  • 4
    Of course you can. It's just a matter of implementing `IEnumerator` and having `MoveNext()` always return true (and hopefully provide a meaningful `Current` value). – Trillian Nov 07 '13 at 03:33
  • 2
    Whose riddle is this? And, have you considered writing a custom `class`, such as one implementing [`IEnumerator`](http://msdn.microsoft.com/en-us/library/78dfe2yb.aspx)? – Jonathan Lonowski Nov 07 '13 at 03:33
  • @Trillian, of course. That should have been in the "no" rules. – sinelaw Nov 07 '13 at 03:34
  • @JonathanLonowski, it's mine (or nobody's) riddle, I was just fiddling with infinite enumerables and got curious. – sinelaw Nov 07 '13 at 03:36
  • You need something that is an `IEnumerable` ... so make a class ... implement `IEnumerable` – ta.speot.is Nov 07 '13 at 03:36
  • @ta.speot.is, yip, updated the rules to not allow that :) – sinelaw Nov 07 '13 at 03:37
  • Stack Overflow is not a riddle and answer site. – ta.speot.is Nov 07 '13 at 03:37
  • 1
    So, "implement infinite IEnumerable without implementing IEnumerable"? – Mike Strobel Nov 07 '13 at 03:39
  • @ta.speot.is, ok - added the [same question on Programmers.StackExchange.com](http://programmers.stackexchange.com/questions/216750/is-it-possible-to-implement-an-infinite-ienumerable-without-using-yield-with-onl). – sinelaw Nov 07 '13 at 03:55
  • 1
    This question appears to be off-topic because it is about programming in general and not a specific question. – Jeremy J Starcher Nov 07 '13 at 05:42

3 Answers3

5
  1. Take the yield example from your question and dump it into Visual Studio.
  2. Compile.
  3. Open in Reflector/ILSpy/dotPeek/etc. and display decompiled sources in C# 1.0 language level (or switch on display of compiler generated sources).
  4. Declare victory, eat cake.
Mike Strobel
  • 25,075
  • 57
  • 69
  • That *would* be interesting - thanks, checking now – sinelaw Nov 07 '13 at 04:05
  • Ok, according to the IL code the compiler generates an anonymous class that implements IEnumerable, so that's that. Interesting to know, though. – sinelaw Nov 07 '13 at 04:20
2

Here is a practically infinite iterator:

using System;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var infiniteIterator =
            Enumerable.Range(Int32.MinValue, Int32.MaxValue)
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .SelectMany(i => Enumerable.Range(Int32.MinValue, Int32.MaxValue))
                      .Select(i => default(int));

        foreach (var infinite in infiniteIterator)
            Console.WriteLine(infinite);
    }
}
ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
  • 2
    Yeah, it is. That's about (2^32)^4 = 2^128 iterations I think. Still not infinite though :) – sinelaw Nov 07 '13 at 04:12
  • I believe the time will end before this thing does (if I'm mistaken add some more `SelectMany` calls), so if your definition of infinite covers a period where time has no definition then sure, it's not infinite. – ta.speot.is Nov 07 '13 at 04:13
1

Use of IEnumerable<T> and yield invokes some C# compiler magic where it wraps the logic into an implementation of IEnumerable, like so:

IEnumerable<T> Infinite<T>() {
    return new Buzzlightyear<T>();
}
private class BuzzLightyear<T> : IEnumerable<T> where T : new() {
    public Boolean MoveNext() { return true; }
    public T Current { return new T(); }
}
Dai
  • 141,631
  • 28
  • 261
  • 374