[coroutine] interface suggestion

my suggestion: 1. the lib provides both coroutine<> and generator<> 2. coroutine<> is special routine allowing to enter and leave a function multiple times 3. coroutine<> first template arg defines the signature of the function accepted by coroutine<> 4. coroutine<>::operator() return type is equal to the return type of signature (template arg) 5. function accepted by coroutine<> first arg allows to suspend coroutine<> == jump back to caller of coroutine<>::operator() -> it has to be discussed if this type is of coroutine<> with an 'inverted' signature (as proposed by Giovanni) or not 6. generator<> returns a set of values in a sequence 7. generator<> has only one template arg defining the return type 8. function accepted by generator<> is required to return void 9. generator<>::operator() returns optional< return_type > 10. generator<> is not a range because - 'A Range provides iterators for accessing a half-open range [first,one_past_last) of elements and provides information about the number of elements in the Range.' -> a generator can not determine how many elements it will return - generator<> can only provide a single pass: 'For any Range a, [boost::begin(a),boost::end(a)) is a valid range, that is, boost::end(a) is reachable from boost::begin(a) in a finite number of increments.' -> if the function accepted by generator<> loops for ever it violates the range invariant typedef generator< int > gen_t; void f( gen_t::caller_t & caller) { while ( true) { caller( 7); } } 11. on top of generator<> something like an iterator could be provided: typedef generator< int > gen_t; gen_t gen( f); enumerator< gen_t > i( gen): enumerator< gen_t > e; while ( i != e) { cout << * i++ << "\n"; } Oliver

Le 19/09/12 09:30, Oliver Kowalke a écrit :
my suggestion:
1. the lib provides both coroutine<> and generator<> I have not think too much about the Giovanni proposal, but what makes coroutine<T()> different from generator<T>?
5. function accepted by coroutine<> first arg allows to suspend coroutine<> == jump back to caller of coroutine<>::operator() -> it has to be discussed if this type is of coroutine<> with an 'inverted' signature (as proposed by Giovanni) or not
6. generator<> returns a set of values in a sequence
7. generator<> has only one template arg defining the return type
8. function accepted by generator<> is required to return void
9. generator<>::operator() returns optional< return_type > I don't see yet why you need optional. The user has the possibility to know if the generator is completed. Using optional adds more constraints
I don't see how you will make the difference between calling a coroutine and yielding the result if the parameter it is coroutine<>. that it solves, as for the time been optional is not movable, isn't it?
10. generator<> is not a range because - 'A Range provides iterators for accessing a half-open range [first,one_past_last) of elements and provides information about the number of elements in the Range.' -> a generator can not determine how many elements it will return I don't see why a range knows about the number of elements !!! - generator<> can only provide a single pass: 'For any Range a, [boost::begin(a),boost::end(a)) is a valid range, that is, boost::end(a) is reachable from boost::begin(a) in a finite number of increments.' You are right, and so any finite generator doesn't violates the range invariant. Maybe the range requirements could be relaxed or a distinction between finite/bounded and infinite/unbounded could be added.
11. on top of generator<> something like an iterator could be provided: typedef generator< int > gen_t; gen_t gen( f); enumerator< gen_t > i( gen): enumerator< gen_t > e; while ( i != e) { cout << * i++ << "\n"; } I don't see the advantage of splitting it in two classes.
typedef generator< int > gen_t; typedef generator< int >::iterator it_t; gen_t gen( f); while ( auto i = gen.begin() != gen.end()) { cout << * i++ << "\n"; } Best, Vicente

On Wed, Sep 19, 2012 at 1:48 PM, Vicente J. Botet Escriba <vicente.botet@wanadoo.fr> wrote:
Le 19/09/12 09:30, Oliver Kowalke a écrit :
10. generator<> is not a range because - 'A Range provides iterators for accessing a half-open range [first,one_past_last) of elements and provides information about the number of elements in the Range.' -> a generator can not determine how many elements it will return
I don't see why a range knows about the number of elements !!!
- generator<> can only provide a single pass: 'For any Range a, [boost::begin(a),boost::end(a)) is a valid range, that is, boost::end(a) is reachable from boost::begin(a) in a finite number of increments.'
You are right, and so any finite generator doesn't violates the range invariant. Maybe the range requirements could be relaxed or a distinction between finite/bounded and infinite/unbounded could be added.
While a generator might not terminate (infinite loop), neither might standard input. Yet Boost.Range has istream_range. We can also say that generator<> only satisfies a range concept if it terminates in a finite number of steps. Now, this not something we can check or infer from the type but the same can be said about any iterator pair. It's the user's responsibility to construct a range (for example using iterator_range class) out of only those iterators that are finite in size. I think not having generators work with ranges would be a disappointment since many, many generators are finite. Regards, Eugene
participants (3)
-
Eugene Yakubovich
-
Oliver Kowalke
-
Vicente J. Botet Escriba