<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx</link><description>I've updated ICollection&amp;lt;A&amp;gt; in the following manner: public interface ICollection &amp;lt;A&amp;gt; : IEnumerable &amp;lt;A&amp;gt; { /// Previous stuff /// &amp;lt;summary&amp;gt; /// Iterates over the members in this collection applying 'p' to each element. /// The return</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135517</link><pubDate>Thu, 20 May 2004 01:53:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135517</guid><dc:creator>AT</dc:creator><description>Framework convert your methods with yield into IEnumerator/IEnumerable delivered class with internal state of method. &lt;br&gt;&lt;br&gt;As you use arbitrary Iterate it's impossible to save current state to restore it on next invocation.&lt;br&gt;&lt;br&gt;As an workaround we can use threading (yep, this is lame).&lt;br&gt;&lt;br&gt;Here is undebugged example:&lt;br&gt;&lt;br&gt;    public virtual IEnumerator&amp;lt;A&amp;gt; GetEnumerator()&lt;br&gt;    {&lt;br&gt;        A current = A.default;&lt;br&gt;        bool finished = false;&lt;br&gt;&lt;br&gt;        AutoResetEvent nextReady = new AutoResetEvent(false);&lt;br&gt;        AutoResetEvent iteratorCanGo = new AutoResetEvent(true);&lt;br&gt;&lt;br&gt;        Predicate&amp;lt;A&amp;gt; pred = delegate(A element)&lt;br&gt;        {&lt;br&gt;            iteratorCanGo.WaitOne();&lt;br&gt;            current = element;&lt;br&gt;            nextReady.Set();&lt;br&gt;            return true;&lt;br&gt;        };&lt;br&gt;&lt;br&gt;        ThreadStart iterator = delegate()&lt;br&gt;        {&lt;br&gt;            try&lt;br&gt;            {&lt;br&gt;                this.Iterate(pred);&lt;br&gt;                iteratorCanGo.WaitOne();&lt;br&gt;            }&lt;br&gt;            finally&lt;br&gt;            {&lt;br&gt;                finished = true;&lt;br&gt;                nextReady.Set();&lt;br&gt;            }&lt;br&gt;        };&lt;br&gt;        Thread t = new Thread(iterator);&lt;br&gt;        t.Start();&lt;br&gt;&lt;br&gt;        while (!finished)&lt;br&gt;        {&lt;br&gt;            nextReady.WaitOne();&lt;br&gt;            if (finished) yield break;&lt;br&gt;            yield return current;&lt;br&gt;            iteratorCanGo.Set();&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;&lt;br&gt;I was unable to find how to better create fiberthreads-like processing in C#. Used two events to signal processing.&lt;br&gt;&lt;br&gt;Note it has at least two (but big) bugs (examples - calling IEnumerator.Reset() or not reading enumeration completely) and not recomemded for any use other that education purpose ;o) !!</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135554</link><pubDate>Thu, 20 May 2004 03:06:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135554</guid><dc:creator>Cyrus Najmabadi</dc:creator><description>AT: I am very scared by your implementation (but I don't think that comes as any suprise to you) :-)&lt;br&gt;&lt;br&gt;Note: I'm not requiring the use of 'yield' and the subsequent compiler manipulations that occur when you do that.  However, I would be interested to know if there was a way (without threading hacks) to create an IEnumerator&amp;lt;A&amp;gt; that worked properly on top of the Iterate method.&lt;br&gt;&lt;br&gt;BTW: IEnumerator&amp;lt;A&amp;gt; doesn't have the reset method like IEnumerator does.  Do we don't need to implement that.</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135599</link><pubDate>Thu, 20 May 2004 04:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135599</guid><dc:creator>SteveJS</dc:creator><description>Waste memory version:&lt;br&gt;&lt;br&gt;         public IEnumerator&amp;lt;A&amp;gt; GetEnumerator()&lt;br&gt;        {&lt;br&gt;            Queue&amp;lt;A&amp;gt; qa = new Queue&amp;lt;A&amp;gt;();&lt;br&gt;            this.Iterate(new Predicate&amp;lt;A&amp;gt;(delegate(A element)&lt;br&gt;            {&lt;br&gt;                qa.Enqueue(element);&lt;br&gt;                return true;&lt;br&gt;            }));&lt;br&gt;            &lt;br&gt;            while (qa.Count != 0)&lt;br&gt;            {               &lt;br&gt;                yield return qa.Dequeue();&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;&lt;br&gt;or Waste time version:&lt;br&gt;&lt;br&gt;        public IEnumerator&amp;lt;A&amp;gt; GetEnumerator()&lt;br&gt;        {                      &lt;br&gt;            Queue&amp;lt;A&amp;gt; qa = new Queue&amp;lt;A&amp;gt;();&lt;br&gt;            this.Iterate(new Predicate&amp;lt;A&amp;gt;(delegate(A element)&lt;br&gt;            {&lt;br&gt;                qa.Enqueue(element);                &lt;br&gt;                return false;&lt;br&gt;            }));&lt;br&gt;            int skip = qa.Count;&lt;br&gt;            while (qa.Count != 0)&lt;br&gt;            {&lt;br&gt;                yield return qa.Dequeue();&lt;br&gt;&lt;br&gt;                int i = 0;&lt;br&gt;                this.Iterate(new Predicate&amp;lt;A&amp;gt;(delegate(A element)&lt;br&gt;                {&lt;br&gt;                    if (i &amp;lt; skip)&lt;br&gt;                    {&lt;br&gt;                        i++;&lt;br&gt;                        return true;&lt;br&gt;                    }&lt;br&gt;                    qa.Enqueue(element);&lt;br&gt;                    return false;&lt;br&gt;                }));&lt;br&gt;                skip += qa.Count;                &lt;br&gt;            }            &lt;br&gt;        }&lt;br&gt;&lt;br&gt;or dynamically waste a little of each:&lt;br&gt;&lt;br&gt;        public IEnumerator&amp;lt;A&amp;gt; GetEnumerator()&lt;br&gt;        {&lt;br&gt;            Queue&amp;lt;A&amp;gt; qa = new Queue&amp;lt;A&amp;gt;();&lt;br&gt;            this.Iterate(new Predicate&amp;lt;A&amp;gt;(delegate(A element)&lt;br&gt;            {&lt;br&gt;                qa.Enqueue(element);&lt;br&gt;                return false;&lt;br&gt;            }));&lt;br&gt;            int skip = qa.Count;&lt;br&gt;            while (qa.Count != 0)&lt;br&gt;            {&lt;br&gt;                while (qa.Count != 0)&lt;br&gt;                {&lt;br&gt;                    yield return qa.Dequeue();&lt;br&gt;                }&lt;br&gt;&lt;br&gt;                int i = 0;&lt;br&gt;                int ct = skip;&lt;br&gt;                this.Iterate(new Predicate&amp;lt;A&amp;gt;(delegate(A element)&lt;br&gt;                {&lt;br&gt;                    if (i &amp;lt; skip)&lt;br&gt;                    {&lt;br&gt;                        i++;&lt;br&gt;                        return true;&lt;br&gt;                    }&lt;br&gt;                    if (ct &amp;gt; 0)&lt;br&gt;                    {&lt;br&gt;                        ct--;&lt;br&gt;                        qa.Enqueue(element);&lt;br&gt;                        return true;&lt;br&gt;                    }&lt;br&gt;                    return false;&lt;br&gt;                }));&lt;br&gt;                skip += qa.Count;&lt;br&gt;            }&lt;br&gt;        }&lt;br&gt;Overall though I'd say you should remove this as a goal for your interface.</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135647</link><pubDate>Thu, 20 May 2004 06:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135647</guid><dc:creator>AT</dc:creator><description>Cyrus: &lt;br&gt;I believe there is no any way to solve this problem without storing state of Iterate function between each  MoveNext() call. &lt;br&gt;&lt;br&gt;So it's not possible to implement your design. You have to push subclasses to implement GetEnumerator and keep states of their Iterate-like functions inside subclasses of IEnumerator&amp;lt;A&amp;gt;.&lt;br&gt;&lt;br&gt;There is very tricky issues with try/catch/finally processing inside Iterate. &lt;br&gt;Consider simple fact - Microsoft was unable to allow yield inside finally and inside any of try with catch and simple catch blocks. &lt;br&gt;Any of this problem prevent from creating reliable method state (which can include not only values of local variables - but also a statuses of exception monitors). But any of this are allowed in your generic Iterate function.&lt;br&gt;&lt;br&gt;I believe that it's theoretically possible to create FSA for exceptions and try/finally blocks - but somebody inside Microsoft decided to not do this complex job.&lt;br&gt;If you will come up with solution for generic Iterate - you will solve all this problem with yield and will be able to integrate them inside compiler.&lt;br&gt;&lt;br&gt;As for my code - I was simply checking if it will really work. Probably this scare you most ;o)&lt;br&gt;Before giving advice to use threading I've to check it first. &lt;br&gt;The major problem with threading is that you do not know that user expect to do with your enumeration - has it finished reading or nope yet. &lt;br&gt;&lt;br&gt;There is no Dispose inside IEnumerator - but this will be good for example for database, filesystem or thread driven enumerations ;o)&lt;br&gt;&lt;br&gt;P.S.&amp;gt; Pay attention to smileys.</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135655</link><pubDate>Thu, 20 May 2004 06:51:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135655</guid><dc:creator>AT</dc:creator><description>SteveJS: &lt;br&gt;Iterate() is not obligated to preserve ordering. &lt;br&gt;There is nothing that must prevent from giving the same elements in different order.&lt;br&gt;&lt;br&gt;But it's a better tradeoff compared to threading ;o)</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135699</link><pubDate>Thu, 20 May 2004 08:31:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135699</guid><dc:creator>Justin Rogers</dc:creator><description>Some interesting links with similar code:&lt;br&gt;&lt;a target="_new" href="http://weblogs.asp.net/justin_rogers/archive/2004/04/30/123780.aspx"&gt;http://weblogs.asp.net/justin_rogers/archive/2004/04/30/123780.aspx&lt;/a&gt;&lt;br&gt;&lt;a target="_new" href="http://weblogs.asp.net/justin_rogers/archive/2004/04/30/123807.aspx"&gt;http://weblogs.asp.net/justin_rogers/archive/2004/04/30/123807.aspx&lt;/a&gt;</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135753</link><pubDate>Thu, 20 May 2004 10:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135753</guid><dc:creator>Cyrus Najmabadi</dc:creator><description>AT: I agree.  I am able to solve the problem with Continuations to transform an internal iterator into an external.  But as those are unavilable in C# I don't see how I can do this.  It's unfortunate because i can do this pretty trivially in Scheme or Ruby. (ok, the code is trivial, understanding the continuations isn't :-) ).  I'm going to do some work to find out what it would take to get mimic the closure functionality I would need in C#.  It's possible to do as well with some sort of freakish use of setjmp longjmp, but I don't know enough IL to know if that possible/allowed.</description></item><item><title>re: Internal and External Iterators</title><link>http://blogs.msdn.com/cyrusn/archive/2004/05/19/135367.aspx#135756</link><pubDate>Thu, 20 May 2004 10:08:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:135756</guid><dc:creator>Cyrus Najmabadi</dc:creator><description>Thanks Justin.  I like how you broke out the logic on whether to continue iterating or not.</description></item></channel></rss>