Tim Jansen's blog


2004/08/27
'yield', generators and coroutines
One of Eek's planned features are coroutines. I have recently discovered this blog entry that shows the use of the 'yield' statement in C#, and it is quite unusual. C#'s 'yield' statement seems to be limited to implementing functions that return the IEnumerable type (C#'s iterator interface). This makes sense in many cases, as every 'yielding' method will return a sequence of values and the number of values may be limited. But it makes it less useful for some purposes in which it can be used just to move variables from the class into the method. Microsoft's implementation is also quite unusual and uses a state machine, more can be found here. The following class shows a co-routine in Eek, the way I want to implement them. The class has a method that adds the argument to the sum of the previous arguments and returns it. 'yield' allows implementing it without any member properties:
class YieldTest
        int accumulate(int a)
                int sum = 0
                while true
                        sum += a
                        yield sum
end
This is the 'yield' that I want for Eek. It works exactly like 'return' and returns the argument, just on the next invocation on the same instance it executes the command after 'yield' instead of restarting the method. In this case the 'while' loop is restarted after yielding the value. The method is a co-routine only because it contains 'yield'. There is no special declaration, as co-routines are just a special case of regular subroutines aka methods. The coroutine ends when the method returns using the regular 'return' statement. This 'return' must always return a value, like a regular 'return'. If the method does not have any return values (or the return values have default values), it is also possible to end the method by executing the last statement. When a coroutine ends it is not allowed to invoke it anymore. Any attempt will return an exception. The state of the coroutine is stored the instance, if the coroutine is an instance method; in the class, if the coroutine is a static method; and in the delegate if the coroutine is a closure. So you can have several 'accumulate()' methods running simultanously, as long as they run in different classes. Co-routines need, as far as I can see, two limitations. The first one is that it must not be allowed to have a 'yield' in a block with 'finally' section or in a 'using' statement. This is not possible, because they are supposed to guarantee a cleanup, but there is no way to guarantee it. The cleanup can't be done immediately after a 'yield' invocation, because there is no guarantee that the co-routine is called again. And cleaning up after every 'yield' does not make any sense. The second limitation is that recursion must not be allowed. Recursion in a co-routine would be quite a mess and I would not know how to implement it. Unfortunately, this restriction means that a co-routine must maintain a flag to prevent recursion. This flag needs to be checked when the co-routine is entered to find out whether it is already running. If yes, an exception is thrown. Otherwise the flag is set, the co-routine executed and then the flag cleared. This solution is easy, but causes an performance impact that makes co-routines slower than regular methods. In some cases it may be possible for the compiler to eliminate the check though. Finally, there is one open point remaining: multi-threading. I am not sure what should happen when two threads try to enter a co-routine simultanously. Because it may mess up the heap, it's probably necessary to prevent this from happening. Unfortunately this requires every co-routine to be locked with a mutex, making it even slower. To get back to the C# implementation, it has one advantage: it makes it easy to implement an IEnumeration, which is probably a very common case. But I expect that with some simple magic and the help of closures, Eek will still be able to return iterators quite easily. This is what a iterator-returning method could look like:
class YieldGeneratorTest
        Iterator countTo5()
                // Generator is a Iterator implementation that takes a coroutine closure.
                return Generator({
                        yield 1
                        yield 2
                        yield 3
                        yield 4
                        return 5
                })
end
I think that example is acceptable, and still cleaner than implementing the Iterator directly like C# does.


 

This blog is my dumping ground for thoughts and ideas about Eek. Someday Eek will be a programming language and system, somewhat comparable to Java in scope. It is my attempt to bring sanity to the world of computing.
At least I hope so. Right now it is far from being finished and I can't guarantee that it ever will be. I am still working on the specification, but I won't release anything before I got my first prototype running. The world does not need more vapourware and unusable beta-software. All publicly available information about Eek is contained in this blog. You can find the latest summary here.
This page is powered by Blogger. Isn't yours? Creative Commons License
This work is licensed under a Creative Commons License.