Talk:Coroutine
This article is rated C-class on Wikipedia's content assessment scale. It is of interest to the following WikiProjects: | ||||||||||||||||||||||||||||
|
Ruby coroutines
[edit]Doesn't Ruby have coroutines? Someone should mention that. --68.35.244.188 05:25, 12 Aug 2004 (UTC)
Python also has coroutines, in the form of the recently (Python 2.3) added generator function. It even has a yield keyword. This could be used to build an excellent example for this article. —Preceding unsigned comment added by 138.38.32.84 (talk • contribs) 2004-11-03 13:26:19
Why did nobody add them? Is there a controversy about whether they really have coroutines?--87.162.67.249 22:13, 9 September 2007 (UTC)
- I am not expert in Ruby, but I believe it has only continuations, not coroutines as such. There is a slight difference. Samohyl Jan 05:32, 10 September 2007 (UTC)
"Editorial" section removed
[edit]I removed the content of the Editorial section, on the grounds that it does not belong in an encyclopedia. I agree that the remaining content in the article is written from a POV that favors the use of coroutines, but the way to fix that is to rewrite the article from NPOV, not add a rebuttal to the article itself. The content follows. Neilc 04:35, 24 Oct 2004 (UTC)
Editorial
[edit]The author of this article clearly has a preference for coroutines over the more popular structures in modern, commercial programming languages. Popularity is by no means a justification for something. However, in this case the alternatives to coroutines are popular for good reason.
Coroutines allowed the "thread of execution", however it is implemented, to enter a function, process it for a while, return to the caller, and go back to the function where it left off while maintaining the state of local variables. This all sounds very useful. It is not. There are much better ways of accomplishing whatever task you wish to perform. I will address some of the issues the author mention above.
In situations in which a coroutine would be the natural implementation of a mechanism, but is not available, the typical response is to create a subroutine that uses an ad-hoc assemblage of boolean flags and other state variables to maintain an internal state between calls.
It is true that most procedural and object-oriented programming languages don't let you jump to the middle of a function. You can in standard Pascal using a goto statement, but it is a bad practice. It is such a bad practice that Borland prohibited it in its Turbo Pascal compiler.
Object-oriented languages such as Java and C++ provide a far more elegant solution. Encapsulate the state information and the operations in a class. The internal state persists between calls to the method because the internal state is associated with members of the class.
- Object-oriented languages do not specifically provide a more elegant solution. You might as well argue that threads as a whole are unnecessary because you can model any number of threads in your application instead with a state machine. This is not eloquent -- using a state machine imperatively to simulate threads. It is much better and easier to write each object such that each object /believes/ it is in its own thread. This is much more natural than writing state machines. You should consider reading: http://www.stackless.com/ —Preceding unsigned comment added by 24.175.26.71 (talk • contribs) 2005-10-07 06:43:25
Threads resemble coroutines on steroids. Threads provide facilities for managing the realtime cooperative interaction of "simultaneously" executing pieces of code. Because they solve a large and difficult problem, they include many powerful and complex facilities and have a concomitantly difficult learning curve. When a coroutine is all that is needed, using a thread seems like overkill.
I do not consider threads to be complex, difficult to learn how to use, or overkill. Multithreaded programming was always simpler than using interprocess communication. In languages like Java, multithreading is extremely simple and easy to use. Two lines of code.
Thread myThread = new Thread(objectThatImplementsRunnable, "My Thread's Name"); myThread.start();
You can even combine these two lines of code into one if you like. So easy. And despite being so easy, threads are extremely efficient. Context switching is almost non-existent in threads. Plus you get pre-emptive multitasking, thread priority, and suspend/resume capability for free.
Threads and object-oriented programming are the way to go. Coroutines may be a nifty concept, but they can't do anything that threads and classes can't do more eloquently.
- Coroutines are for many tasks easier than threads. Consider for instance you want to program a state machine. Without threads or coroutines, you need to remember state, and with each call of the procedure implementing state machine make a jump by the state. This will result in somewhat clumsy and hard-to-read code, because entry point must know how to deal with all states, not only outgoing ones. With threads, you could do this, but you also have to explicitly synchronize them (because you really don't need concurrency for this task). But coroutines make implementation of this easy and natural. For instance, this can be used to program agents in games, where each agent is essentially a state machine, and they interact. Then it nicely separates code for each agent from the rest (main loop), without hassle about synchronization and locking, because they are in fact executed sequentially. Samohyl Jan 10:36, 26 August 2005 (UTC)
- I agree with this. You're missing the point if you think that coroutines and threads are tools for the same purpose. They are most certainly not. Pointedly, coroutines can be used (such as in Stackless Python) to provide thread-like behavior for a massive number of independent objects. For example, you could have 100,000 objects each of which is written in a thread-like manner. No real OS could manage that number of threads in a practical way. However, you can write such a system with coroutines. Note that your result is effectively cooperative multitasking, where threads traditionally use pre-emptive multitasking. —Preceding unsigned comment added by 24.175.26.71 (talk • contribs) 06:40, 7 October 2005 (UTC)
Coroutines originated in languages Simula and Modula-2,
[edit]BLISS programming language - what about this ? —Preceding unsigned comment added by 195.42.89.34 (talk • contribs) 2005-12-29 13:35:45
??? For that matter, they originated before BLISS. They were a recognized assembly-language technique. In fact I think that's how Knuth presents coroutines. Dpbsmith (talk) 14:46, 29 December 2005 (UTC)
Implementation does not require garbage collector
[edit]The Detailed Comparison portion contains
- In contrast, coroutines, able to call on other coroutines as peers, are best implemented using continuations (which in turn are implemented using a garbage-collected heap) to track the flow of control
As demonstrated by the portable coroutines library linked at the bottom of the page, you don't need a garbage-collected heap to implement continuations. There's nothing unique about a continuation as an object and in fact since in many C libraries coroutines are not copyable (I think that's generally true) and have a defined lifecycle (when the coroutine hits the end of execution, it dies), there's not even a need for reference counting. One think that's interesting about coroutines is that the memory for one can be preallocated and trivially reused (making their creation rather cheap).
I'm going to update this wording. AnthonyLiguori
called vs. peer coroutines
[edit]I don't understand the difference described in this section. I looked for the terms on Google, but I didn't find any explanation. Maybe an example (especially of language that makes this distinction) or at least a citation would be helpful. Samohyl Jan 07:27, 16 July 2006 (UTC)
(moved here)
Hi, Whiner01. Regarding your recent edits at coroutine (about peer and called coroutines). I don't understand the distinction from your description, and I tried to look for some reference of this terminology, but failed. Can you provide an example of a language that actually makes such distinction, and explain the actual difference between the two kinds of coroutines? I know coroutines in Python, and there is no need for such distinction. Samohyl Jan 18:06, 17 July 2006 (UTC)
I came across the word "coroutine" somewhere. I wanted to pin it down because so many times i encounter the term "coroutine" in contexts where it is not justified. "Coroutine" is too often a buzzword whose meaning is not known to the person using it. Google IS sparse on the term. Forgotten by many and puffed out of shape by others.
I was frustrated by an article that didn't tell me much. The discussion page shows a removal of an editorialization on whether or not coroutines are as neat as threads. Very profound.
I tried to roll in what i learned about coroutines from assembly language. I didn't want to exclude any possibilities. Some concrete examples from programming languages might help, but i worry if the language implementations don't exclude meaningful possibilities. If a language "fails to make a distinction", could it mean that they omitted a major form, or it could mean that they found a unification that was not expressed here before, and that i also missed? Can you provide a link to a good discussion of the Python implementation of coroutines?
The few examples on the page and near-at-hand are not very informative. They fail to show or tell why coroutines might be useful, and why understanding of coroutines might be educational. The similarity to subroutines is important, but so is the similarity to threads. The example(s) here don't have a complete syntax.
I re-embroidered from what was here, and so i might be out on a limb. BUT, the examples clearly fall into one style of usage or another. Some speak of "call", or at least "return"ing of values, and some speak of "yield"ing control. The discussions themselves have created two styles, with two grammars. I just spelled it out. I admit i am somewhat lost as to how coroutines are coded in a compiled language. Greater complexities come from the possibility of passing parameters. Parameters can make it so gritty, that I wonder if they bother with parameters at all.
I can easily envision a main program with a coroutine, the coroutine having the maximum resemblance to a subroutine. The coroutine declares formal parameters. The program can "call" the coroutine from many places with actual parameters. At each call, the new parameters are re-passed to the coroutine code. The co-routine starts or resumes each time it is called. It can return from many places. In most languages a subroutine can return only one value, which stores back into the main program by an assigment of the result of the coroutine call. There is an asymmetry here: the main program can jam in multiple parameters, but it can only get back one. But i guess the coroutine could modify its arguments, just like subroutines do. And one earlier assumption need not be locked in: maybe the coroutine can declare different formal parameters at each re-entry point. Why not?
Code for a coroutine -- in a language that uses only one set of formal parameters for the coroutine:
Coroutine add3(a): static t do t=a return -1 t+=a return -1 t+=a return t loop
Code for a coroutine -- in a language that uses one set of formal parameters for each [re-]entry:
Coroutine add3: do co-entry(a) return -1 co-entry(b) return -1 co-entry(c) return a+b+c loop
Putting the coroutines on a more equal standing requires a deeper rearrangement of the program syntax. Both coroutines need to have formal parameters declared -- either once at the top, or once at each re-entry. But then how does the first co-routine get started? If a co-routine has declarations at the top, then it cannot also be a main program. There has to be a stub of a main program that falls into one coroutine or the other. How does one of the coroutines get to be declared the main coroutine? Or does the main program have to call one of the coroutines? But then there are two ways in, co-call and call -- not very elegant.
If we allow that there is an "acceptor" declaration to receive formal parameters, the coding of the coroutines will show something interesting. The first co-routine to execute has a co-call before the following accept clause. All other co-routines have an accept clause preceding any co-call statement. A reminder that parameter passing complicates things? Or just a reminder that there has to be a main program.
So, how are coroutines declared in Python, etc.?
--Whiner01 06:07, 18 July 2006 (UTC)
Support of coroutines under several languages seems to consist of pages of debate on how it should be done. Support in other languages seems to involve schedulers, which is not what coroutines are supposed to be about. In other languages, coroutines "can be executed concurrently", so they are something completely unrelated to previous discussions.
--Whiner01 06:36, 18 July 2006 (UTC)
- First, before I address your questions, I must said that I consider your changes to article very messy and confusing (both stylistically and factually). Could you please refrain from editing while we have this sorted out? As you said, you have little knowledge of coroutines yourself, so you probably should think twice before making substantial changes to this article, and also the terminology you use may well be unsuitable for Wikipedia, according to WP:OR policy (I am not such a big expert too, so that's why I am actually asking for references to support your claims or terminology).
- To your question about Python. Python coroutines are similar to standard Python functions (which can return many values in single pass, thanks to Python tuples or dictionaries), but treated quite differently. If the coroutine is first called, it will return another callable object, which then remembers its state (both instruction pointer and local variables) and can be called repeatedly, and also another parameters can be passed into it. So the first call is very different from subsequent calls. The coroutine returns from the subsequent calls using yield keyword (which is also way how the compiler recognizes it as a coroutine). The reasons for this particular implementation are historic, but though it can look ugly from inside, the usage tends to be pretty elegant actually. The discussion of Python coroutine implementation can be found in the PEPs [1] and [2].
- I think the problem you have with coroutine is that you want them to have work in the same way as normal subroutines. But they are different - the coroutine needs to be initialized to work properly. Also, the coroutines are not here to address the problem with passing multiple parameters out of a function - you can pass structure to do that. Also, I don't think it's good idea to allow jump anywhere into the same coroutine (with perhaps different input parameters), just as it isn't a good idea to allow this for a normal function; this is an assembler way of doing things, not a high-level language way (it's almost like infamous goto statement).
- I hope I addressed your questions. Samohyl Jan 18:02, 18 July 2006 (UTC)
- Just to clear up things up: Python does not have true coroutines, in the sense that other coroutine-supporting languages use the term. What PEP 342 defines is a simple enhancement to Python's generator functionality, which makes it easier and more convenient to implement (some would say "emulate") what real coroutines do (that's why the PEP title is "Coroutines via Enhanced Generators"). --Piet Delport 04:15, 19 July 2006 (UTC)
I have again stumbled into a muddy topic. I can't yet cite Knuth yet because I have to go and find a paper copy of his foundational computer writings.
You are free to inject facts into the article.
For example, the very first sentence of the article contradicts your claim that coroutine is not a subroutine: "In computer science, coroutines are program components that generalize subroutines ...". (The first sentence is of course wrong. Many implementations of coroutines work that way, but a coroutine can be other things.)
The examples shown in Python also fail to provide any counter-example. They only show coroutines that are called and then return values by yielding, as if that was the only kind of coroutine.
The poorly written example in the article shows a different kind of coroutine using "yield to" which implies that the coroutine gets to decide which other coroutine it yields to! (Assuming there are more than two.) That is a distinct thing. I don't see "yield to" in any other examples. Maybe "yield to" does not exist -- but then it's not my facts that are wrong -- the example predates my edits. But coroutines go back to the assembler era, and "yield to" surely existed somewhere.
Coroutine is first of all a concept! The idea of cooperating equals. Two patches of code in the same program, both written as if they are the main program. And switching between each other instantly and effortlessly, or at least as easily subroutine calls and without ever involving a separate thread or a scheduler.
The concept quickly fragments, even before implementation begins. Coroutines can be done in assembler because everything is "roll your own". Similarly, in many languages, coroutines can be done as "roll your own" using switch statements and state variables. After that, macros to hide the ugly switch statements built into the code.
It is hard to roll all of the coroutine possibilities into a compiled language. It is easier to make an elegant version of coroutines by omitting some of the possibilities. A called coroutine fits very neatly into the compiled era. The main program can freely call subroutines and coroutines; subroutines and coroutines can freely call subroutines and coroutines. Even so, I'm surprised it took so long for a called coroutine to get some standard keywords.
Complicating the use of the term coroutine is that people are constantly finding other meanings for it. In "BETA" (i think), they talk about coroutines running "concurrently". WTF.
--Whiner01 01:31, 19 July 2006 (UTC)
- I thought about it a little and I think I understand what you mean. When you call a coroutine in Python, it works much as a function call, ie. the return address is recorded somewhere, and you can track the path back (by yielding). But you are right, in the example and perhaps other languages it's more like a jump (or goto) into a function. So, back to the article. Perhaps we could simply say that resuming a coroutine is in some languages like a call (ie. the return address is recorded) and in other languages it is (perhaps) as a jump or goto into a function (so the return address is lost). If you agree, I will rewrite the first paragraph (after the intro) in this sense. Samohyl Jan 19:14, 19 July 2006 (UTC)
I ran out of time to tinker with this one. (Possibly an "event horizon" effect. The article stops getting needed edits or rewrites when it gets too big or complicated to edit or rewrite on one sitting.) In the past I have gotten away with making substantial improvements to pages i did not understand, learning as i go. For example, Fat binary. I hypothesized that a utility must exist that can "remove the fat' from a fat binary. Another editor provided the fact, a utility called "lipo". Under Coroutine, i hypothesized that there are coroutines that can return but not yield. It apparently works that way under C#, with a "yield return" statement.
There are huge problems with the term as "Coroutine" as commonly used and discussed. There is the original notion, predating the popularity of threads and multiprocessing. Coroutines are still the ultimate lightweight thread, even in the days of threading, because of the infinitesimal consumption of resources and the instantaneous [micro-]context switching. Knuth was not the first; the idea of two main programs that trade off has been in print since 1958. Details of the original notion and Knuth's notion, which i have not yet looked up. Many many implementations, home-grown under assembler and many languages. Implementations in languages, most of which are faulty or incomplete, tedious, risky, etc. Modern non-implementations that include fake co-routines using threads, etc. People who think that their particular implementation defines the concept.
Call and Return have native hardware support and acceleration. The method of passing mountains of arguments through the same call-and-return stack is an outgrowth of necessity even for assembly-language programs, which is formalized and highly used in compiled languages. Allocating all local or temporary (non-"static") variables onto a bloated call-and-return stack is another method best managed by languages. It provides for very quick (instant) disposal of the temporary variables. (Passing data through the stack also provides for the helpful and useful "buffer overrun" errors that cross up data and addresses, making every compiled program vulnerable to hijacking.)
Coroutines are far from standardized. Coroutines have no hardware support. Support in languages, if any, is in its infancy. There are many complications and many possibilities for implementation. The possibility of parameters and return values adds its own complexity. Each implementation fails to deliver most or all of the possibilities and adds unnecessary complications of its own. Giving a coroutine every functional possibility probably complicates the support structure so much as to nullify the advantages. Implementing coroutines is supposed to be simple, but (for example) how does one allow recursive [called] coroutines? (or does recusrsing mean anything at all?)
In some languages (or pseudo-languages), you "call" a coroutine and then "resume" the coroutine. But then they say you can "call" it every time and it figures out what to do. A co-routine that does a "yield return" then has no way of actually ending -- the code can fall off the end. Does that code implicitly loop, or does the coroutine die somehow? Yield and return (or "yield return") are far different concepts.
Coroutines that are implemented allowing "yield TO" are vastly different from the callable kind. The main program becomes implicitly a coroutine that can be yielded to.
--Whiner01 08:25, 23 July 2006 (UTC)
- See my earlier comment: what you seem to be talking about here (the feature found in C#, Python, and such), are not coroutines at all, but generators. Even though both concepts involve control flow, and both use the word "yield" (to mean various things), they're two distinct things, using two different techniques to solve two different sets of problems.
- (Things get slightly confused by the fact that you can implement generators in terms of coroutines, and vica versa (with a bit more trouble), but that does not make them any more similar. The situation is sort of like closures versus objects: either can be implemented entirely in terms of the other, but despite that they don't bear much resemblance in terms of how they're usually used, implemented, and reasoned about.) --Piet Delport 21:34, 24 July 2006 (UTC)
nop 12:32, 20 September 2007 (UTC)
- I just wanted to know what coroutine is about. Unfortunately, the introduction was not very clear. I found that Simon Tatham's intro is far more intuitive than the gibberish cited in external links. I tried to modify the introduction to make it more comprehensive.
It's still unclear to me what the difference between generators and coroutines is. Are coroutines really supposed to direct scheduling? Are they truly forbidden from returning values? (Simon Tatham's article is very instructive, but unhelpful on this point.) If you can't explain what the difference is (other than by reference to outright snobbery) then perhaps they are actually the same concept. At which point I suppose we ought to consider merging the pages on Wikipedia…Donal Fellows (talk) 10:37, 11 September 2008 (UTC)
Lua coroutines
[edit]Someone should note that coroutines are standard in lua. —Preceding unsigned comment added by Chokosabe (talk • contribs) 2007-04-01 13:33:56
C# yield return statement
[edit]Does the yield return statement in C# fit in here? 220.245.146.199 11:47, 13 September 2007 (UTC)
- If it specifies where it's yielding to, then yes; otherwise, add it to generator (computer science). EdC 21:43, 13 September 2007 (UTC)
Green Thread?
[edit]The definition of Green Threads seems identical to the historic definition of Coroutines. Only if you insist that a Coroutine cannot suspend in a subroutine (i.e. suspend when there is call stack or context) would there be any difference.
The term Green Thread is quite "new". Coroutines in Simula (and early C++ versions) worked exactly like Green Threads. DRW - Oct 8, 2007 —Preceding unsigned comment added by 207.59.232.138 (talk) 15:55, 8 October 2007 (UTC)
Coroutines in Tcl
[edit]Tcl 8.6 will have coroutines; I've not added it to the list of programming languages yet because that's still a version in beta. Of course, it strictly has generators, but the generator semantics allows the passing of a value upon reentry after yield and a bunch of other things that makes the functionality more coroutine like, and many other languages are in the list despite being generators as well. Note that we won't have a direct “yield to”; that's considered to not fit with the way that the rest of the language operates. Donal Fellows (talk) 15:15, 8 January 2009 (UTC)
Coroutine in Scheme
[edit]FYI, I just came across a very nice, very simple, elegant example implementation of coroutines in scheme, using just a continuation and a queue, and posted it on the Talk:Continuation page. I think it deserves to be in some article somewhere, just not sure where. linas (talk) 15:58, 22 August 2009 (UTC)
reference style
[edit]I would like to consistently use {{Cite foo}}
tempalates and {{Reflist|refs=...
in this article. The former for consistency and the latter for decluttering the text. I've started on this effort and plan to continue if there are no objections; so feel free to revert and set me straight here! Thanks, ErikHaugen (talk) 21:00, 26 October 2010 (UTC)
coexpressions in Icon
[edit]For anyone feeling that the historical role of Ralph Griswold et al Icon programming language is not given its due here, I would note the recent changes to the implementation in Robert Parlett's ObjectIcon at code.google.com/p/objecticon
I have added a link to CLU at the Icon article
G. Robert Shiplett 00:06, 16 June 2012 (UTC)
Use in Game Development
[edit]Coroutines are a useful pattern for game development. In this area, one often wants to expose a scripting-language to designers or developers, without giving them access to threading mechanisms which require careful tuning and centralized control for high-performance. The rendering-frame or simulation frame (typically from 15 Hz to 60 Hz) means that most tasks need to be broken-up into actions that can happen in (much) less than the frame time. Storing state in objects, as mentioned in the editorial section, is one way to do this, but leads to a proliferation of boiler-plate code. For instance, creating state enums, switching on the object's current state, etc. Code can be clearer, and therefore more maintainable if it is visible at a glance, has straight-line flow, and is contained in a few-line coroutine, rather than dispersed through multiple locations in the sources.
Coroutines in the Unity Game Engine: http://docs.unity3d.com/Documentation/Manual/Coroutines.html
Coroutines in Lua (an often used extension-language for games): http://www.lua.org/pil/9.1.html
Jawa0 (talk) 15:20, 1 November 2013 (UTC)
Stale external link
[edit]The external links section contains a stale reference to [explanation of coroutines. This URL no longer works. JR Bouvier (talk) 17:49, 30 December 2013 (UTC)
- I removed it; feel free to fix stuff. ErikHaugen (talk | contribs) 18:43, 30 December 2013 (UTC)
Clarification please
[edit]I can't make sense of this sentence:
- The difference between calling another coroutine by means of "yielding" to it and simply calling another routine (which then, also, would return to the original point), is that the latter is entered in the same continuous manner as the former.
Also, the term "yield" is not properly introduced before it's used. Encyclopedant (talk) 23:45, 4 August 2014 (UTC)
External links modified
[edit]Hello fellow Wikipedians,
I have just modified one external link on Coroutine. Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
- Corrected formatting/usage for http://www.ruby-forum.com/topic/126011
When you have finished reviewing my changes, please set the checked parameter below to true or failed to let others know (documentation at {{Sourcecheck}}
).
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}}
(last update: 5 June 2024).
- If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
- If you found an error with any archives or the URLs themselves, you can fix them with this tool.
Cheers.—cyberbot IITalk to my owner:Online 01:35, 1 April 2016 (UTC)
Emulating with trampoline
[edit]You say that generators are weaker since their yield supplies no label to jump to. You immediately demonstrate that `yield to consumer` can be emulated with generators by `yield consumer`. This is a joke to me. You had to drop `to consumer` instead of only `to` particle in order to transform the code into generators. How does dropping `to` particle work? --Javalenok (talk) 06:25, 7 December 2016 (UTC)
C++ coroutines TS
[edit]A new entry is needed under the C++ section, namely the coroutines TS (technical specification). It proposes a C++ standard for stackless coroutines that will very likely be in C++20. Three major compilers, Visual C++, gcc, and Clang already support major portions, in the std::experimental namespace. Here's a link to the TS: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4680.pdf — Preceding unsigned comment added by 2600:1700:E840:AC40:64DB:84F0:639C:A8E3 (talk) 00:02, 29 March 2018 (UTC)
Programming languages with native support
[edit]While seeking information, I found a questionable citation that I replaced with a better URL, which only illustrates a technique. The questionable citation was introduced in 2013. --Ancheta Wis (talk | contribs) 13:36, 13 January 2019 (UTC)
Definition
[edit]What are the defining features of a coroutine? (How do different authors theoretically define coroutines, and do different major programming languages differ in what sort of object is/isn't termed a coroutine?)
For example are all these neccessary and sufficient for a block of code to be a general coroutine:
- Multiple entry points (not only the beginning of the block). (Is this always implemented as a statement that temporarily yields control then resumes at the following line?)
- Repeated bidirectional information passing i.e. the code can send new information each time it yields control, and can receive new information each time it resumes execution. (Presumably this piece of information is always sent to/from the same section of code as which control is passing to/from at that same instant?)
- Retention of state (local variables) while the block of code is suspended. (Is this implemented differently from the typical stack?)
- Ability for that block of code to yield control to other than its own caller. (?)
How are coroutines different from subroutines that call other subroutines? (I.e. a call statement cooperatively passes control to someplace else, and later the execution may resume from the next line). Is the difference that subroutines have a hierarchical stack structure (i.e. a subroutine can call a new subroutine or return to its own caller, but cannot directly pass control back to another routine that is deeper in the call stack)? Do coroutines facilitate flow graphs containing cycles?
Does "coroutine" have any meaning in entirely functional, rather than proceedural, programming paradigms (say, Lisp, Mathematica)?
In object-oriented programming, is message-passing (method calling) between objects a full implementation of coroutines? (Is it a problem that calling a send/receive method will always pass control to the start of that method?)
Does making full use of coroutines require launching them from an event loop (like in Python)?
The original 1963 coroutines paper seems to describe communication between coroutines as analogous (in syntax) to how a traditional program makes IO (read/write) calls. They were intended for multistage data processing pipelines, letting different-stage modules run concurrently/asynchronously so that data can be streamed through the entire pipeline in a single pass (akin to nesting generators in Python) without needing to cache any intermediate dataset in full. Is the coroutine concept more general than nested generators?
Cesiumfrog (talk) 02:33, 5 September 2019 (UTC)
- I had the same confusion. But I've added section Definition and Types lately. You may take a look. Thanks. Gqqnb (talk) 12:37, 28 January 2023 (UTC)
Coroutines vs Threads in hard realtime contexts
[edit]The Comparison with threads section contains
- The advantages of coroutines over threads are that they may be used in a hard-realtime context (switching between coroutines need not involve any system calls or any blocking calls whatsoever), there is no need for synchronisation primitives such as mutexes, semaphores, etc. in order to guard critical sections, and there is no need for support from the operating system.
I'm not sure what would be the best way to fix it, but I don't think this is correct. Hard realtime just means that missing the deadline is an error, i.e. never occurs if the software is correct, as opposed to only degrading performance or quality in some way. Some systems have synchronisation primitives, including mutexes, with operations that can be guaranteed to complete in a bounded amount of time, which means they can be used with no risk of missing a deadline. --119.18.1.113 (talk) 03:25, 27 August 2020 (UTC)
- Good points. An issue I see is that the section seems to imply that threads cannot (at all) be used in hard-realtime contexts, and that coroutines are the (only?) way to go. Maybe it could be rewritten so that coroutines are portrayed as one way of switching context (with little OS support) these systems. Chrisma0 (talk) 08:55, 27 August 2020 (UTC)
Lost History?
[edit]In reading this article on coroutines, it appears to me that this term does not mean what it did 50 years ago. I would like to direct everyone's attention to an article called Moving FORTH by Brad Rodriguez. If you look at the section called Indirect Threaded Code you will see three short routines called NEXT, ENTER and EXIT which are truly coroutines. They do not call each other they simply jump to each other based on the code being handled. While the code is executing a function these three coroutines bounce back and forth between the three of them. When the DUP code is called a different coroutine is executed in place of ENTER, and when it completes it jumps back to NEXT without invoking EXIT. If a data element is called, the coroutine for that data element's type is called in place of ENTER. In this way they allow the Virtual Machine they are in to operate efficiently. There are NO subroutine calls involved. The return stack never gets an address to return to one of these routines. There is a return stack being used, but it is associated with the position in the bytecode routine being scanned. I believe that these coroutines exemplify the meaning of what it means to be a coroutine.
If you go back and investigate who was on the team that wrote the COBOL compiler with Melvin Conway (who authored the referenced article [2] which gave coroutines their name) you will probably find Chuck Moore the author of FORTH whose work inspired the Moving FORTH article. 50.206.176.154 (talk) 01:23, 22 April 2021 (UTC)
Coroutine/generator terminology confusion
[edit]There are 2 different 'basic' types of coroutine.
- Symmetric coroutines. There is only one operator, `yield to`, and this transfers control to another coroutine.
- Asymmetric coroutines. There are two operators, `resume` and `yield`. `resume` transfers control to another coroutine, and then control is transferred back when it performs a `yield`.
There are two more potential distinctions between types of coroutine.
- Stackful coroutines. You can use `resume`/`yield`/`yield to` within a function call, and when the coroutine recieves control again it continues from within that function call. Yielded coroutines retain their own call stack.
- Stackless coroutines. You cannot use `yield` or `yield to` within a function call. Yielded coroutines do not retain their own call stack.
There is another distinction which only applies to asymmetric coroutines.
- Output-only coroutines. `resume` cannot transfer values into the coroutine, but `yield` can transfer them out.
- Input-output coroutines. Both `resume` and `yield` can transfer values.
This article confuses these distinctions in some way. In the section comparing 'coroutines' with 'generators', it defines 'coroutine' as referring to symmetric coroutines, and 'generator' as referring to asymmetric ones. It seems to imply that 'coroutines' are more expressive than 'generators', and I would disagree, but that's a subjective matter.
Later on in the article, languages like Lua, Python and JavaScript are considered to have 'coroutines'. Both of these languages actually have asymmetric, input-output coroutines, which this article considers 'generators'. These ought to be mentioned in the Generator article, but they're not, they're here.
Python's section in the article implies that the 'generator'/'coroutine' distinction is one of output-only/input-output, rather than symmetric/asymmetric as was defined earlier. This seems to be how the Python community defines the distinction, but this discrepancy should be mentioned.
Overall, this article is very inconsistent and conflates several different flavours of coroutine with each other. This was inevitable as the terminology is completely inconsistent in general usage, and seems to vary between languages. However, both this article and the Generator article should inform about these inconsistencies, rather than feeding into them. Rdococ1 (talk) 18:37, 4 February 2022 (UTC)
- I agree. The academia doesn't have a common definition of coroutine, which leads to the loose logic of this article. What's more, people also have divided views of whether the coroutine in a language, eg. Python, is stackful or stackless. Gqqnb (talk) 04:24, 31 October 2022 (UTC)