
Hi Boost community, Despite I´m a newby using Boost, I wanted to ask some users about a very old yet useful idea: the continuations. As an experiment, I made an extremely simple example of how a continuation could look like in C++, and now I was wondering either how can Boost and this concept make benefit of each other: in the case of the concept, what´s the best way to implement continuations using boost, and in the case of boost, whether a new library or extension to functional can be extended to support this feature. The design goals I setted are: - avoid usage of stack and recursion - basic design principles (such as Law of Demeter) compliancy - avoid complex iterative functions for implementing iterative algorithms - provide both a standard way of implementing this, and a platform-specific calling convention with compiler hacks - maximize simplicity In order to test the idea, I made a very simple test implementing a classic factorial using continuations. The ´library´ part of my code is: template <class INFO> class Caller { public: typedef void Continuation(Caller<INFO>& caller, INFO& info); private: INFO& info; Continuation* next; public: Caller(Continuation* ini, INFO& init_info) : info(init_info), next(ini) {} void operator()() { while (next != NULL) next(*this, info); } void stop_calling() { next = NULL; } void set_next(Continuation* cont) { next = cont; } }; /////////////////////////// And the factorial example is: //////////// struct Info { int level; int result; }; void fun2(Caller<Info>& caller, Info& info) { if (info.level > 0) { info.result *= info.level; info.level--; } else caller.stop_calling(); } void fun1(Caller<Info>& caller, Info& info) { info.result = 1; info.level = 5; caller.set_next(fun2); } int main() { Info info; Caller<Info> c(fun1, info); c(); cout << info.result << endl; } Now the three questions: - how can this be best implemented using boost? - is this of enough interest so to be an enhancement of functional, or even a new library? - could Boost provide a mix of calling-convention plus library implementation (compiler-specific) so the above example could be even simpler? I can think of some g++ hacks. Thanks, and my apologies if this isn´t the proper place to post this. Sincerely, Daniel Gutson.

Daniel Gutson wrote:
Hi Boost community, Despite I´m a newby using Boost, I wanted to ask some users about a very old yet useful idea: the continuations.
See Boost.Coroutine, which already implements this.
- provide both a standard way of implementing this, and a platform-specific calling convention with compiler hacks
setjmp/longjmp for portability, makecontext/swapcontext on POSIX systems, fibers on MS Windows.

Hi Mathias, thanks for answering. I found such library in Vault, so it´s not in another place, right? I found also the continuation namespace, but as far as I saw, yes this is a generalization of the concept, but focused in coroutines, and somehow (as far as I understand) in concurrent programming. The concept I´m referring here (which, of course could be incorrect) is not related with concurrent programming, multithreading or iterators, but the ability to specify an execution flow without using a stack (I´m somewhat messed with embedding programming), and a neat support for iterative algorithms implementations. Please let me know if I´m in the same page you are, and thanks for your patience. Regarding your mention to ucontext, setjmp and others, yes this could be implemented partly using them. Thanks again! Daniel. On 9/25/07, Mathias Gaunard <mathias.gaunard@etu.u-bordeaux1.fr> wrote:
Daniel Gutson wrote:
Hi Boost community, Despite I´m a newby using Boost, I wanted to ask some users about a very old yet useful idea: the continuations.
See Boost.Coroutine, which already implements this.
- provide both a standard way of implementing this, and a platform-specific calling convention with compiler hacks
setjmp/longjmp for portability, makecontext/swapcontext on POSIX systems, fibers on MS Windows.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 9/25/07, Daniel Gutson <danielgutson@gmail.com> wrote:
Hi Mathias, thanks for answering.
I found such library in Vault, so it´s not in another place, right?
You mean boost-coroutine in the concurrency folder of the vault? [http://tinyurl.com/278qca] You can also find the documentation here: http://www.crystalclearsoftware.com/soc/coroutine/index.html And access the SVN here: http://svn.boost.org/trac/boost/browser/sandbox/SOC/2006/coroutine Note that the name is misleading. Boost.Coroutine is not yet a boost library. I haven't even submitted it for review yet (even if it is practically finished and the documentation almost done) for lack of time.
I found also the continuation namespace, but as far as I saw, yes this is a generalization of the concept, but focused in coroutines, and somehow (as far as I understand) in concurrent programming.
Well, coroutines and one-shot continuations are dual as there is a simple transformation from one to the other [1]. On the other hand, the word 'continuation' alone in computer science usually refers to true restartable continuations which are *extremely* hard to do in C++ (you would need a way to copy the stack reliably). The UNIX fork() syscall is what get closer to true continuations in the C world (except that it also copy the global state, but you can get around that). What you are showing in your example are simple stack less (you can't yield from inside a call stack) coroutines. My coroutine library supports the stackfull variant of coroutines. It cannot be implemented within the standard C++, so it uses a range of OS specific services (make_context and Win32 Fibers) or custom assembler. They could also be implemented fairly portably on top of boost.thread, but I haven't done so yet. I expect such an implementation to be fairly slow. Boost.coroutine is definitely not focused on concurrent programming. In fact the documentation states clearly that often coroutines are mistaken for poor man threads, which they are not. Threads and coroutines are orthogonal. One of the library example is in fact the classic factorial and it looks like this (namespaces stripped for simplicity): typedef coroutine<double()> coroutine_type; size_t factorial(coroutine_type::self& self) { double n = 0; double n_bang = 1; self.yield(n_bang); while(true) { n_bang = n_bang * ++n; self.yield(n_bang); } } int main() { coroutine_type fact(factorial); for(int i = 0; i <100; i++) std::cout <<i<<"!= "<<fact()<<"\n"; }
The concept I´m referring here (which, of course could be incorrect) is not related with concurrent programming, multithreading or iterators, but the ability to specify an execution flow without using a stack (I´m somewhat messed with embedding programming), and a neat support for iterative algorithms implementations.
Boost.Coroutine provides yield_next which is the equivalent of your set_next, but that is just syntactic sugar, because a coroutine library without yield_next is just as powerful one without. Yield_next could be emulated by just returning the next coroutine to jump to. I provide it in the library because it is slightly more efficient to be implement natively (you save a stack switch and an indirect call). BTW, yield next is just a more powerful variant of goto, which means that you are more likely of shooting yourself in the foot :) gpd [1] http://www.inf.puc-rio.br/~roberto/docs/corosblp.pdf

Hi Giovanni, thanks for answering too. Sorry I don´t quote on your text, it´s easier for me to write simple conclusions. - one of the goals of the small program I showed as example, was, as you mentioned, to be ´stack-less´, since this is thought for small embedded devices. - the most similar feature that you describe is the yield_next, since one of the things I wanted to avoid (in the ´client´ part) is the loop control (i.e. the ´while´), leaving it to the library part. That being said, is there any implementation sample of the factorial using yield_next? - what are the ´overheads´ and (O.S.) dependencies of yield_next? - maybe the term ´continuation´ was not the best one for describing what I was trying to do. Thanks Giovanni! Daniel. On 9/26/07, Giovanni Piero Deretta <gpderetta@gmail.com> wrote:
On 9/25/07, Daniel Gutson <danielgutson@gmail.com> wrote:
Hi Mathias, thanks for answering.
I found such library in Vault, so it´s not in another place, right?
You mean boost-coroutine in the concurrency folder of the vault? [http://tinyurl.com/278qca]
You can also find the documentation here:
http://www.crystalclearsoftware.com/soc/coroutine/index.html
And access the SVN here:
http://svn.boost.org/trac/boost/browser/sandbox/SOC/2006/coroutine
Note that the name is misleading. Boost.Coroutine is not yet a boost library. I haven't even submitted it for review yet (even if it is practically finished and the documentation almost done) for lack of time.
I found also the continuation namespace, but as far as I saw, yes this is a generalization of the concept, but focused in coroutines, and somehow (as far as I understand) in concurrent programming.
Well, coroutines and one-shot continuations are dual as there is a simple transformation from one to the other [1]. On the other hand, the word 'continuation' alone in computer science usually refers to true restartable continuations which are *extremely* hard to do in C++ (you would need a way to copy the stack reliably). The UNIX fork() syscall is what get closer to true continuations in the C world (except that it also copy the global state, but you can get around that).
What you are showing in your example are simple stack less (you can't yield from inside a call stack) coroutines. My coroutine library supports the stackfull variant of coroutines. It cannot be implemented within the standard C++, so it uses a range of OS specific services (make_context and Win32 Fibers) or custom assembler. They could also be implemented fairly portably on top of boost.thread, but I haven't done so yet. I expect such an implementation to be fairly slow.
Boost.coroutine is definitely not focused on concurrent programming. In fact the documentation states clearly that often coroutines are mistaken for poor man threads, which they are not. Threads and coroutines are orthogonal. One of the library example is in fact the classic factorial and it looks like this (namespaces stripped for simplicity):
typedef coroutine<double()> coroutine_type; size_t factorial(coroutine_type::self& self) { double n = 0; double n_bang = 1; self.yield(n_bang); while(true) { n_bang = n_bang * ++n; self.yield(n_bang); } }
int main() { coroutine_type fact(factorial); for(int i = 0; i <100; i++) std::cout <<i<<"!= "<<fact()<<"\n"; }
The concept I´m referring here (which, of course could be incorrect) is not related with concurrent programming, multithreading or iterators, but the ability to specify an execution flow without using a stack (I´m somewhat messed with embedding programming), and a neat support for iterative algorithms implementations.
Boost.Coroutine provides yield_next which is the equivalent of your set_next, but that is just syntactic sugar, because a coroutine library without yield_next is just as powerful one without. Yield_next could be emulated by just returning the next coroutine to jump to.
I provide it in the library because it is slightly more efficient to be implement natively (you save a stack switch and an indirect call).
BTW, yield next is just a more powerful variant of goto, which means that you are more likely of shooting yourself in the foot :)
gpd
[1] http://www.inf.puc-rio.br/~roberto/docs/corosblp.pdf _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

On 9/27/07, Daniel Gutson <danielgutson@gmail.com> wrote:
Hi Giovanni, thanks for answering too.
Sorry I don´t quote on your text, it´s easier for me to write simple conclusions.
- one of the goals of the small program I showed as example, was, as you mentioned, to be ´stack-less´, since this is thought for small embedded devices.
If with stack-less you mean you do not have a per-coroutine stack [1], yes, this might be a worthy goal. There upsides and downsides. The upsides are: - can be implemented with standard c++. - might give compilers a better chance to optimize (could in principle inline across yields). - better control over 'local object allocation' Downsides: - code inside the coroutine must be written with a coroutine in mind. With my coroutine library this isn't necessary. Think for example of running regex_match in a coroutine passing it an iterator that yields when there isn't enough data instead of blocking. This way you can use boost.regex in a non blocking fashion (i.e with asio), while with your approach you need to modify boost regex to handle this case. - you can't yield from inside a call stack. - manual local object allocation. You can't allocate objects that span the whole coroutine lifetime in the stack. You need to allocate them in a special area. If some of these objects have overlapping lifetimes, the compiler has a very hard job optimizing them, while it would be much easier if they where allocated on the stack.
- the most similar feature that you describe is the yield_next, since one of the things I wanted to avoid (in the ´client´ part) is the loop control (i.e. the ´while´), leaving it to the library part. That being said, is there any implementation sample of the factorial using yield_next?
No, I do not have one at the moment, but it is pretty straight forward. It would look similar to your example. I see that in this case you *really* want to do without a stack. Probably boost.coroutine is not for you.
- what are the ´overheads´ and (O.S.) dependencies of yield_next?
On the optimal assembler implementation, a bouch of push and pops and an indirect function call (wich is the most expensive instruction of the lot). The fiber implementation might or might not be slightly higher. The makecontext implementation is hopeless as it need to call into the kernel to change the sigmask (many order of magnitude slower).
- maybe the term ´continuation´ was not the best one for describing what I was trying to do.
Actually I think yes, it is, In a certain sense what are you trying to do is continuation passing style for control flow, using a function pointer + state as a continuation, and doing tail call optimization by hand. HTH, gpd [1] Just to clarify: I usually use the terms stackful and stackles terms to refer to coroutine that can or can't respectively yield from inside a call stack. You seem to use the term in the stackless-python sense, that is, emulating the local object stack outside of the C++ native stack.
participants (3)
-
Daniel Gutson
-
Giovanni Piero Deretta
-
Mathias Gaunard