C++ Logo

std-proposals

Advanced search

Re: inline coroutine generators

From: Phil Endecott <std_proposals_list_at_[hidden]>
Date: Thu, 09 Dec 2021 19:04:23 +0000
Jason McKesson wrote:
> On Thu, Dec 9, 2021 at 11:28 AM Phil Endecott via Std-Proposals
> <std-proposals_at_[hidden]> wrote:
>>
>> Dear Experts,
>>
>> I have recently been experimenting with generators for the
>> first time.
>>
>> One issue that bothers me is inlining. For example:
>>
>> generator<char> g1()
>> {
>> for (.....) {
>> co_yield x;
>> if (......) g2(a);
>> if (......) g2(b);
>> g2(a+b);
>> }
>> }
>>
>> static ??? g2(int)
>> {
>> for (....) {
>> co_yield ....;
>> }
>> }
>>
>> What I'm trying to convey with that pseudocode is that I've
>> decomposed a largish block of code by factoring out some common
>> bits into another routine.
>
> "Inlining" does not mean you get to ignore C++'s rules. An inline
> function that issues a return doesn't cause the function that called
> it to return to *its* caller. If your intent is for `g2`'s `co_yield`
> to cause `g1` to yield, then you can't.

Well this is the std::proposals list, so yes I do get to ignore
the (current) rules in the sense that I can imagine a change if
I want to...

Seriously though, thinking of co_yield as analogous to return is
not the only way to think about it. Consider:

   void g1(function<...> callback)
   {
      callback(1);
      g2(callback);
   }

   void g2(function<...> callback) // or auto invocable callback
   {
     callback(2);
   }

Here I'm passing a callback function which is invoked with the values
that the routine "yields". (It's almost possible to convert between
this style and a generator with search-and-replace.) With callbacks,
I can pass the callback function to the nested function with no problem
and invoke it from there with no overhead.

Note that yielding (and suspending in general) from a nested function
in a coroutine is something that is possible in stackfull coroutines
like Boost.Coroutine2. Does anyone know what other languages do?


> Some people have suggested ways to write some kind of named statements
> or expressions that behaves as if it were within the invoking code.
> But along that road lies madness. It becomes *way* too easy to hide
> control flow.

I take your point that this is complicating control flow and
that can lead to bad code. Like many features in C++ it would be
possible to mis-use.


Marcin Jaczewski wrote:
> Basic solution is simply `co_yield g2(a)` and then make a complex
> implementation in `generator<char>` that handles nested generators.
> When you yield on another generator it will redirect the outer
> generator `++` to this inner `++`.

Right, I know how that works. It adds a lot of overhead, which I
think is unavoidable i.e. we cannot imagine that a future compiler
will be able to eliminate it.


Regards, Phil.

Received on 2021-12-09 13:04:26