none
IX problem when creating an enumerable using IYielder RRS feed

  • Question

  • I have decided to play with IX a little bit and re-implement Unfold function from F# using the same signature. Here is what I got:

            public static IEnumerable<TResult> Unfold<TState, TResult>(TState initialState, 
                Func<TState, Tuple<TResult, TState>> generator)
            {
                return EnumerableEx.Create<TResult>(yielder =>
                    {
                        var currentState = initialState;
                        while (true)
                        {
                            var next = generator(currentState);
                            if (next == null)
                            {
                                yielder.Break();
                                return;
                            }
                            currentState = next.Item2;
                            yielder.Return(next.Item1);
                        }
                    });
            }

    But, when I tried to use it:

                var fibs = EnumerableEx1
                    .Unfold(Tuple.Create(0, 1),
                            x => Tuple.Create(x.Item1, Tuple.Create(x.Item2, x.Item1 + x.Item2)))
                    .Take(10)
                    .ToList();

    I got a strange error: "Inheritance security rules violated while overriding member: 'System.Linq.Yielder`1<T>.UnsafeOnCompleted(System.Action)'. Security accessibility of the overriding method must match the security accessibility of the method being overriden."

    Is this a bug in IX?

    Actually, I don't quite understand the purpose of the .Create override that uses Action(IYielder) - it seems all the same can be done with built-in yields, for example:

            public static IEnumerable<TResult> Unfold<TState, TResult>(TState initialState,
                Func<TState, Tuple<TResult, TState>> generator)
            {
                var currentState = initialState;
                while (true)
                {
                    var next = generator(currentState);
                    if (next == null)
                        yield break;
                    currentState = next.Item2;
                    yield return next.Item1;
                }
            }
    

    Wednesday, May 8, 2013 6:29 PM

Answers

  • Yes, this is indeed a bug! It is on our list to fix for Ix.

    Your question about the .Create overload is spot-on--you should be able to do the same with built-in yields, but you currently cannot in C#. In C#, yield cannot appear inside of a lambda, though interestingly it can in VB.

    Also, you should note that you may have a performance hit if you use this .Create overload to workaround the yield restriction, as it uses async and Task under the hood. The specific behavior would depend a lot on your use case, of course.

    Donna Malayer
    Developer, Rx Team

    • Proposed as answer by Rx team Tuesday, May 28, 2013 10:44 PM
    • Marked as answer by Sergey Aldoukhov Tuesday, May 28, 2013 10:47 PM
    Tuesday, May 28, 2013 10:44 PM