Topic: Coroutines and state machines (N4244, N4134)


Author: David Krauss <potswa@gmail.com>
Date: Wed, 29 Oct 2014 16:06:17 +0800
Raw View
--Apple-Mail=_9E531428-EAA5-4B81-88B0-E8F4B687BD2F
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8

I=E2=80=99ve been thinking about coroutines over the past week, while I was=
 offline on vacation. I just want to share these ideas as incremental contr=
ibutions.

Coroutines are similar to finite-state machines, and the C-legacy, switch-b=
ased idioms for the two patterns have a lot of overlap. Rather than extrapo=
late from use cases of coroutines (generators, consumers), we should levera=
ge general FSM principles to maximize expressiveness.

An FSM is defined by a set of states including an initial and perhaps a ter=
minal state, conditions which lead from one state to another depending on i=
nput values, and output values and actions which are taken upon a transitio=
n or upon reaching a state.

I propose mapping these essential properties to C++:
states =3D> suspension point statements
transitions =3D> function calls on the coroutine functor
input values =3D> parameter/argument lists
output values =3D> return values
actions =3D> statements in function body
initial state =3D> coroutine object construction
terminal state =3D> function scope exit

This mapping should resolve various issues such as:
Yielded-object aliasing, which has been raised the thread =E2=80=9Ccomment =
on n4244=E2=80=9D on this list.
The potential to pass zero or several values to a coroutine before resuming=
 it, or to yield zero or several values before suspending. These possibilit=
ies add either UB or runtime check overhead.
Common errors such as forgetting to explicitly specify or query initial and=
 final states. Such errors have appeared in examples in the other thread (=
=E2=80=9Cwriting simple generators,=E2=80=9D which appears in a message in =
the thread =E2=80=9CComment on N4244=E2=80=9D with capitalization).

Subexpressions like await or yield from are a poor way to receive input val=
ues because subexpression evaluation is unsequenced, so it makes no sense t=
o have more than one such subexpression in a full-expression. Also it cause=
s the suspension point to be indeterminately sequenced with side effects of=
 the full-expression that do not depend on it. Finally, there may be constr=
aints on the location of suspension points, such as the provision in N4134 =
that exception handling cannot be suspended.

Suspension points should have:
clear sequencing
ability to receive arbitrary new values
easily-identifiable context relative to surrounding statements
ability to externally identify the state
These constraints point toward an await statement:

await ( parameter-declaration-clause ) statement

To identify the states, a coroutine object has an unscoped member enumerati=
on states and a nonstatic member named state. Each await statement which is=
 labeled adds its label as an enumerator. (The enumeration values are unspe=
cified. The standard should not guarantee portability of state values acros=
s builds of the same program.) The standard may reserve initial, terminal, =
state, and states as label identifiers within coroutines. It would be prefe=
rable to have a scoped enumeration, but using it would require naming the c=
losure type, which is difficult. Some extension to scoped enumerations coul=
d alleviate this issue.

For convenience, a coroutine object should contextually convert to bool wit=
h the result being state =3D=3D terminal.

When suspending, a coroutine should be able to return by reference or by va=
lue. Different FSM transitions may in general produce different output valu=
e types, although in most cases return values are homogeneous. I propose th=
at return statements produce output values, and that the rules for return t=
ype deduction be relaxed. If a resumable lambda is declared with a (trailin=
g, non-placeholder) return type, then it always generates that type. Otherw=
ise, all return statements are deduced separately (the default return type =
being auto, i.e. by value), subject to the constraints below.

Suspension comprises returning an output and awaiting further input, and te=
rmination is the same except without any await. There needs to be some inte=
raction between a return statement and a subsequent await statement, with s=
ome constraints:
Several transitions may lead to or from the same state.
Execution must stop at the return or the await, whichever comes last.
Each transition has a particular return type, suggesting constraints on the=
 return statements.
An observable state of the FSM may signal a different return type.
A coroutine may not jump into its own state transition.

These constraints are difficult to satisfy, but here=E2=80=99s what I have =
so far.
An await statement shall be preceded immediately by a return statement, not=
 considering enclosing selection or iteration statements if-else, for, whil=
e, do, and switch (note, break cannot precede await). Any intervening condi=
tions are evaluated. If control is not transferred to an await statement, t=
he next state is terminal (and control is returned immediately to the calle=
r).
A return statement may be augmented with a compound statement, which is exe=
cuted after the return value expression is evaluated. This prevents contort=
ions to refactor computations before the return statement or inside the con=
ditions.
If a return statement compound statement is exited by a jump statement (con=
tinue or goto), any await statement(s) at the target location may be execut=
ed. However, those await statements still must be preceded by a return. (Th=
is incidentally prevents break from working.)
A jump statement inside a return statement shall potentially lead to an awa=
it. Any other jump statement shall not.
return expression continue; is shorthand for return expression { continue; =
}. return expression goto label; is shorthand for return expression { goto =
label; }.
All unlabeled await statements reachable from a particular return statement=
 shall have identical parameter types. These form a state-subset.
All return statements reachable from a particular state-subset or labeled a=
wait statement shall have the same return type.
Labeled await statements are assigned to state-subsets by partitioning all =
states according to input (await parameter) and output (return expression) =
types.
All states of a state-subset are implemented by a member function with the =
corresponding signature. When two states would differ only by the output (r=
eturn) type, the member function is a template taking a non-type parameter =
of states type. Any of the constituent states of a set selects the same imp=
lementation. The primary template is defined as deleted. (The user will sel=
dom need this, so omitting the template argument should produce a diagnosti=
c mentioning the variant return types.)

This approach easily allows several awaits to follow a return, correspondin=
g to diverging FSM paths. Its treatment of loops models FSM cycles. Converg=
ing cyclic FSM paths from several returns back to one await is easily done =
with continue. More random patterns require goto, but there are few use cas=
es and such use of goto should actually reflect current practices pretty we=
ll: it=E2=80=99s not unintuitive that a state machine should goto a state.

For generators, an initial return statement is required to advance past the=
 initial state, to either the generative state or the terminal state. Witho=
ut this, there is no representation of the empty sequence.

auto accumulate_proto =3D [] ( int max ) resumable {
// initial:
    return; // Leave initial state.

    for ( int i =3D 0; // Initialization occurs before transition.
            i < max; // Comparison occurs before every suspension to genera=
tive state.
            ) {
    generative:
        await ( int addend ) {
            return i +=3D addend continue;
        }
    }
    // This is unreachable.
}; // Construct copyable object.

auto countup0 =3D countup;
assert ( countup0.state =3D=3D countup.initial );
countup0( 0 ); // Initialize FSM.
assert ( countup0.state =3D=3D countup.terminal );

auto countup3 =3D countup;
assert ( countup3.state =3D=3D countup.initial );
countup3( 3 ); // Initialize FSM.
assert ( countup3.state =3D=3D countup.generative );
assert ( countup3( 1 ) =3D=3D 1 );
assert ( countup3( 2 ) =3D=3D 3 );
assert ( countup3.state =3D=3D countup.terminal );

The unreachability at the end and the difficulty of appending another seque=
nce to the end of the generator seem to be weaknesses, so the design space =
might need more exploration. However, idiomatic safety with empty sequences=
 in the common case is pretty important. Without the initial return, the in=
itial await is invalid. The extra call for FSM initialization can be elimin=
ated by jumping over the initial return and into the loop body with goto, b=
ut users generally shouldn=E2=80=99t do so.

Finally, it is sometimes useful to suspend a coroutine upon an exception in=
stead of to terminate. There may be a try await statement, which does not b=
ehave as await statements above, except that if it is labeled, the label is=
 added as a state enumerator. This statement behaves like a normal try bloc=
k, except that a suspension point precedes it, and there may be no catch bl=
ocks after it. The coroutine is suspended before any exception would propag=
ate out of it (or its catch blocks, if any). Unwinding continues with the c=
aller.

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

--Apple-Mail=_9E531428-EAA5-4B81-88B0-E8F4B687BD2F
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8

<html><body style=3D"word-wrap: break-word; -webkit-nbsp-mode: space; -webk=
it-line-break: after-white-space;">I=E2=80=99ve been thinking about corouti=
nes over the past week, while I was offline on vacation. I just want to sha=
re these ideas as incremental contributions.<div><br></div><div>Coroutines =
are similar to finite-state machines, and the C-legacy, switch-based idioms=
 for the two patterns have a lot of overlap. Rather than extrapolate from u=
se cases of coroutines (generators, consumers), we should leverage general =
FSM principles to maximize expressiveness.</div><div><br></div><div>An FSM =
is defined by a set of states including an initial and perhaps a terminal s=
tate, conditions which lead from one state to another depending on input va=
lues, and output values and actions which are taken upon a transition or up=
on reaching a state.</div><div><br></div><div>I propose mapping these essen=
tial properties to C++:</div><div><ul class=3D"MailOutline"><li>states =3D&=
gt; suspension point statements</li><li>transitions =3D&gt; function calls =
on the coroutine functor</li><li>input values =3D&gt; parameter/argument li=
sts</li><li>output values =3D&gt; return values</li><li>actions =3D&gt; sta=
tements in function body</li><li>initial state =3D&gt; coroutine object con=
struction</li><li>terminal state =3D&gt; function scope exit</li></ul><div>=
<br></div></div><div>This mapping should resolve various issues such as:</d=
iv><div><ul class=3D"MailOutline"><li>Yielded-object aliasing, which has be=
en raised the thread =E2=80=9Ccomment on n4244=E2=80=9D on this list.</li><=
li>The potential to pass zero or several values to a coroutine before resum=
ing it, or to yield zero or several values before suspending. These possibi=
lities add either UB or runtime check overhead.</li><li>Common errors such =
as forgetting to explicitly specify or query initial and final states. Such=
 errors have appeared in examples in the other thread (=E2=80=9Cwriting sim=
ple generators,=E2=80=9D which appears in a message in the thread =E2=80=9C=
Comment on N4244=E2=80=9D with capitalization).</li></ul></div><div><br></d=
iv><div>Subexpressions like <font face=3D"Courier">await</font> or <font fa=
ce=3D"Courier">yield from</font> are a poor way to receive input values bec=
ause subexpression evaluation is unsequenced, so it makes no sense to have =
more than one such subexpression in a full-expression. Also it causes the s=
uspension point to be indeterminately sequenced with side effects of the fu=
ll-expression that do not depend on it. Finally, there may be constraints o=
n the location of suspension points, such as the provision in N4134 that ex=
ception handling cannot be suspended.</div><div><br></div><div>Suspension p=
oints should have:</div><div><ul class=3D"MailOutline"><li>clear sequencing=
</li><li>ability to receive arbitrary new values</li><li>easily-identifiabl=
e context relative to surrounding statements</li><li>ability to externally =
identify the state</li></ul></div><div>These constraints point toward an <f=
ont face=3D"Courier">await</font> statement:</div><div><br></div><div><font=
 face=3D"Courier">await</font> <font face=3D"Courier">(</font> <i>parameter=
-declaration-clause</i> <font face=3D"Courier">)</font>&nbsp;<i>statement</=
i></div><div><br></div><div>To identify the states, a coroutine object has =
an unscoped member enumeration&nbsp;<font face=3D"Courier">states</font> an=
d a nonstatic member named <font face=3D"Courier">state</font>. Each&nbsp;<=
span style=3D"font-family: Courier;">await</span>&nbsp;statement which is l=
abeled adds its label as an enumerator. (The enumeration values are unspeci=
fied. The standard should not guarantee portability of state values across =
builds of the same program.) The standard may reserve <font face=3D"Courier=
">initial</font>,&nbsp;<font face=3D"Courier">terminal</font>,&nbsp;<span s=
tyle=3D"font-family: Courier;">state</span>, and <font face=3D"Courier">sta=
tes</font> as label identifiers within coroutines. It would be preferable t=
o have a scoped enumeration, but using it would require naming the closure =
type, which is difficult. Some extension to scoped enumerations could allev=
iate this issue.</div><div><br></div><div>For convenience, a coroutine obje=
ct should contextually convert to <font face=3D"Courier">bool</font> with t=
he result being <font face=3D"Courier">state =3D=3D terminal</font>.</div><=
div><br></div><div>When suspending, a coroutine should be able to return by=
 reference or by value. Different FSM transitions may in general produce di=
fferent output value types, although in most cases return values are homoge=
neous. I propose that return statements produce output values, and that the=
 rules for return type deduction be relaxed. If a resumable lambda is decla=
red with a (trailing, non-placeholder) return type, then it always generate=
s that type. Otherwise, all return statements are deduced separately (the d=
efault return type being&nbsp;<font face=3D"Courier">auto</font>, i.e. by v=
alue), subject to the constraints below.</div><div><br></div><div>Suspensio=
n comprises returning an output and awaiting further input, and termination=
 is the same except without any await. There needs to be some interaction b=
etween a <font face=3D"Courier">return</font> statement and a subsequent <f=
ont face=3D"Courier">await</font> statement, with some constraints:</div><d=
iv><ul class=3D"MailOutline"><li>Several transitions may lead to or from th=
e same state.</li><li>Execution must stop at the <font face=3D"Courier">ret=
urn</font> or the <font face=3D"Courier">await</font>, whichever comes last=
..</li><li>Each transition has a particular return type, suggesting constrai=
nts on the return statements.</li><li>An observable state of the FSM may si=
gnal a different return type.</li><li>A coroutine may not jump into its own=
 state transition.</li></ul></div><div><br></div><div>These constraints are=
 difficult to satisfy, but here=E2=80=99s what I have so far.</div><div><ul=
 class=3D"MailOutline"><li>An <font face=3D"Courier">await</font> statement=
 shall be preceded immediately by a <font face=3D"Courier">return</font> st=
atement, not considering enclosing selection or iteration statements <font =
face=3D"Courier">if</font>-<font face=3D"Courier">else</font>,&nbsp;<font f=
ace=3D"Courier">for</font>, <font face=3D"Courier">while</font>, <font face=
=3D"Courier">do</font>, and&nbsp;<font face=3D"Courier">switch</font> (note=
,&nbsp;<font face=3D"Courier">break</font> cannot precede <font face=3D"Cou=
rier">await</font>). Any intervening conditions are evaluated. If control i=
s not transferred to an <font face=3D"Courier">await</font> statement, the =
next state is <font face=3D"Courier">terminal</font>&nbsp;(and control is r=
eturned immediately to the caller).</li><li>A <font face=3D"Courier">return=
</font> statement may be augmented with a compound statement, which is exec=
uted after the return value expression is evaluated. This prevents contorti=
ons to refactor computations before the return statement or inside the cond=
itions.</li><li>If a <font face=3D"Courier">return</font> statement compoun=
d statement is exited by a jump&nbsp;statement (<font face=3D"Courier">cont=
inue</font>&nbsp;or&nbsp;<font face=3D"Courier">goto</font>), any <font fac=
e=3D"Courier">await</font> statement(s) at the target location may be execu=
ted. However, those await statements still must be preceded by a return. (T=
his incidentally prevents&nbsp;<span style=3D"font-family: Courier;">break<=
/span>&nbsp;from working.)</li><li>A jump statement inside a <font face=3D"=
Courier">return</font> statement shall potentially lead to an <font face=3D=
"Courier">await</font>. Any other jump statement shall not.</li><li><font f=
ace=3D"Courier">return</font><i> expression </i><font face=3D"Courier">cont=
inue;</font> is shorthand for <font face=3D"Courier">return<i style=3D"font=
-family: Helvetica;">&nbsp;expression&nbsp;</i>{ continue; }</font>. <font =
face=3D"Courier">return</font> <i>expression</i> <font face=3D"Courier">got=
o</font> <i>label</i><font face=3D"Courier">;</font> is shorthand for&nbsp;=
<span style=3D"font-family: Courier;">return</span><i>&nbsp;expression&nbsp=
;</i><span style=3D"font-family: Courier;">{&nbsp;<font face=3D"Courier">go=
to</font><span style=3D"font-family: Helvetica;">&nbsp;</span><i style=3D"f=
ont-family: Helvetica;">label</i>; }</span>.</li><li>All unlabeled&nbsp;<fo=
nt face=3D"Courier">await</font> statements reachable from a particular <fo=
nt face=3D"Courier">return</font> statement shall have identical parameter =
types. These form a <i>state-subset</i>.</li><li>All <font face=3D"Courier"=
>return</font> statements reachable from a particular state-subset or label=
ed <font face=3D"Courier">await</font> statement shall have the same return=
 type.</li><li>Labeled <font face=3D"Courier">await</font> statements are a=
ssigned to state-subsets by partitioning all states according to input (<fo=
nt face=3D"Courier">await</font> parameter) and output (<font face=3D"Couri=
er">return</font> expression) types.</li><li>All states of a state-subset a=
re implemented by a member function with the corresponding signature. When =
two states would differ only by the output (return) type, the member functi=
on is a template taking a non-type parameter of <font face=3D"Courier">stat=
es</font> type. Any of the constituent states of a set selects the same imp=
lementation. The primary template is defined as deleted. (The user will sel=
dom need this, so omitting the template argument should produce a diagnosti=
c mentioning the variant return types.)</li></ul></div><div><br></div><div>=
This approach easily allows several <font face=3D"Courier">await</font>s to=
 follow a <font face=3D"Courier">return</font>, corresponding to diverging =
FSM paths. Its treatment of loops models FSM cycles. Converging cyclic FSM =
paths from several <font face=3D"Courier">returns</font>&nbsp;back to one <=
font face=3D"Courier">await</font> is easily done with <font face=3D"Courie=
r">continue</font>. More random patterns require&nbsp;<font face=3D"Courier=
">goto</font>, but there are few use cases and such use of <font face=3D"Co=
urier">goto</font> should actually reflect current practices pretty well: i=
t=E2=80=99s not unintuitive that a state machine should <font face=3D"Couri=
er">goto</font> a state.</div><div><br></div><div>For generators, an initia=
l return statement is required to advance past the initial state, to either=
 the generative state or the terminal state. Without this, there is no repr=
esentation of the empty sequence.</div><div><br></div><div><div><font face=
=3D"Courier">auto accumulate_proto =3D [] ( int max ) resumable {</font></d=
iv><div><font face=3D"Courier">// initial:</font></div><div><font face=3D"C=
ourier">&nbsp; &nbsp; return; // Leave initial state.</font></div><div><fon=
t face=3D"Courier"><br></font></div><div><font face=3D"Courier">&nbsp; &nbs=
p; for ( int i =3D 0; // Initialization occurs before transition.</font></d=
iv><div><font face=3D"Courier">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i =
&lt; max; // Comparison occurs before every suspension to generative state.=
</font></div><div><font face=3D"Courier">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=
 &nbsp; ) {</font><div><font face=3D"Courier">&nbsp; &nbsp; generative:</fo=
nt></div><div><font face=3D"Courier">&nbsp; &nbsp; &nbsp; &nbsp; await ( in=
t addend ) {</font></div><div><span style=3D"font-family: Courier;">&nbsp; =
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return i +=3D addend continue;</span></d=
iv><div><span style=3D"font-family: Courier;">&nbsp; &nbsp; &nbsp; &nbsp; }=
</span></div><div><span style=3D"font-family: Courier;">&nbsp; &nbsp; }</sp=
an></div></div></div><div><span style=3D"font-family: Courier;">&nbsp; &nbs=
p; // This is unreachable.</span></div><div><span style=3D"font-family: Cou=
rier;">}; // Construct copyable object.</span></div><div><span style=3D"fon=
t-family: Courier;"><br></span></div><div><span style=3D"font-family: Couri=
er;">auto countup0 =3D countup;</span></div><div><div><font face=3D"Courier=
">assert ( countup0.state =3D=3D&nbsp;countup.initial );</font></div><div><=
/div></div><div><span style=3D"font-family: Courier;">countup0( 0 ); // Ini=
tialize FSM.</span></div><div><div><font face=3D"Courier">assert ( countup0=
..state =3D=3D&nbsp;countup.terminal );</font></div><div></div></div><div><s=
pan style=3D"font-family: Courier;"><br></span></div><div><span style=3D"fo=
nt-family: Courier;">auto countup3 =3D countup;</span></div><div><div><font=
 face=3D"Courier">assert ( countup3.state =3D=3D&nbsp;countup.initial );</f=
ont></div><div></div></div><div><span style=3D"font-family: Courier;">count=
up3( 3 );</span><span style=3D"font-family: Courier;">&nbsp;</span><span st=
yle=3D"font-family: Courier;">// Initialize FSM.</span></div><div><font fac=
e=3D"Courier">assert ( countup3.state =3D=3D&nbsp;countup.generative );</fo=
nt></div><div><font face=3D"Courier">assert ( countup3( 1 ) =3D=3D 1 );</fo=
nt></div><div><font face=3D"Courier">assert ( countup3( 2 ) =3D=3D 3 );</fo=
nt></div><div><div><div><div><font face=3D"Courier">assert ( countup3.state=
 =3D=3D&nbsp;countup.terminal );</font></div><div><font face=3D"Courier"><b=
r></font></div><div></div></div></div></div><div>The unreachability at the =
end and the difficulty of appending another sequence to the end of the gene=
rator seem to be weaknesses, so the design space might need more exploratio=
n. However, idiomatic safety with empty sequences in the common case is pre=
tty important. Without the initial <font face=3D"Courier">return</font>, th=
e initial <font face=3D"Courier">await</font> is invalid. The extra call fo=
r FSM initialization can be eliminated by jumping over the initial return a=
nd into the loop body with <font face=3D"Courier">goto</font>, but users ge=
nerally shouldn=E2=80=99t do so.</div><div><br></div><div>Finally, it is so=
metimes useful to suspend a coroutine upon an exception instead of to termi=
nate. There may be a&nbsp;<font face=3D"Courier">try await</font> statement=
, which does not behave as <font face=3D"Courier">await</font> statements a=
bove, except that if it is labeled, the label is added as a state enumerato=
r. This statement behaves like a normal <font face=3D"Courier">try</font> b=
lock, except that a suspension point precedes it, and there may be no <font=
 face=3D"Courier">catch</font> blocks after it. The coroutine is suspended =
before any exception would propagate out of it (or its catch blocks, if any=
). Unwinding continues with the caller.</div><div><br></div></body></html>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

--Apple-Mail=_9E531428-EAA5-4B81-88B0-E8F4B687BD2F--

.


Author: Gor Nishanov <gornishanov@gmail.com>
Date: Wed, 29 Oct 2014 22:00:24 -0700 (PDT)
Raw View
------=_Part_365_1750394973.1414645224865
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Interesting angle. I did not fully absorbed your proposal, so i cannot=20
comment on its detail yet.

But I have a comment on methodology of developing generic abstractions=20
suggested by Stepanov.

(Me paraphrasing, I don't even remember which lecture / paper he described=
=20
it)

Start from the best solution to a given problem on a given platform, try to=
=20
discern the abstraction that can make that pattern easily and safely=20
repeatable.
Apply your abstraction to the problem you derived it from. Is it an=20
improvement? No perf regression? Good. Now try to apply it to some other=20
problem which looks similar.
Keep iterating until you are satisfied.

For N4134 (and I think N4244 as well), the primary problem to solve was=20
capturing the best patterns of efficient async programs (interacting state=
=20
machines where async completions drive the state machines) and capture the=
=20
pattern in the coroutine.
Given that abstraction apply it to something else, generators, for example.

Note, it was not meant to be a general purpose state machine abstraction.=
=20
It was targeting specific kind of state machines that can be represented as=
=20
a coroutine.

Gor

for await (x: S) { bla } statement. I think it is something that=20



On Wednesday, October 29, 2014 1:06:32 AM UTC-7, David Krauss wrote:

> I=E2=80=99ve been thinking about coroutines over the past week, while I w=
as=20
> offline on vacation. I just want to share these ideas as incremental=20
> contributions.
>
> Coroutines are similar to finite-state machines, and the C-legacy,=20
> switch-based idioms for the two patterns have a lot of overlap. Rather th=
an=20
> extrapolate from use cases of coroutines (generators, consumers), we shou=
ld=20
> leverage general FSM principles to maximize expressiveness.
>
> An FSM is defined by a set of states including an initial and perhaps a=
=20
> terminal state, conditions which lead from one state to another depending=
=20
> on input values, and output values and actions which are taken upon a=20
> transition or upon reaching a state.
>
> I propose mapping these essential properties to C++:
>
>    - states =3D> suspension point statements
>    - transitions =3D> function calls on the coroutine functor
>    - input values =3D> parameter/argument lists
>    - output values =3D> return values
>    - actions =3D> statements in function body
>    - initial state =3D> coroutine object construction
>    - terminal state =3D> function scope exit
>
>
> This mapping should resolve various issues such as:
>
>    - Yielded-object aliasing, which has been raised the thread =E2=80=9Cc=
omment=20
>    on n4244=E2=80=9D on this list.
>    - The potential to pass zero or several values to a coroutine before=
=20
>    resuming it, or to yield zero or several values before suspending. The=
se=20
>    possibilities add either UB or runtime check overhead.
>    - Common errors such as forgetting to explicitly specify or query=20
>    initial and final states. Such errors have appeared in examples in the=
=20
>    other thread (=E2=80=9Cwriting simple generators,=E2=80=9D which appea=
rs in a message in=20
>    the thread =E2=80=9CComment on N4244=E2=80=9D with capitalization).
>
>
> Subexpressions like await or yield from are a poor way to receive input=
=20
> values because subexpression evaluation is unsequenced, so it makes no=20
> sense to have more than one such subexpression in a full-expression. Also=
=20
> it causes the suspension point to be indeterminately sequenced with side=
=20
> effects of the full-expression that do not depend on it. Finally, there m=
ay=20
> be constraints on the location of suspension points, such as the provisio=
n=20
> in N4134 that exception handling cannot be suspended.
>
> Suspension points should have:
>
>    - clear sequencing
>    - ability to receive arbitrary new values
>    - easily-identifiable context relative to surrounding statements
>    - ability to externally identify the state
>
> These constraints point toward an await statement:
>
> await ( *parameter-declaration-clause* ) *statement*
>
> To identify the states, a coroutine object has an unscoped member=20
> enumeration states and a nonstatic member named state. Each await stateme=
nt=20
> which is labeled adds its label as an enumerator. (The enumeration values=
=20
> are unspecified. The standard should not guarantee portability of state=
=20
> values across builds of the same program.) The standard may reserve=20
> initial, terminal, state, and states as label identifiers within=20
> coroutines. It would be preferable to have a scoped enumeration, but usin=
g=20
> it would require naming the closure type, which is difficult. Some=20
> extension to scoped enumerations could alleviate this issue.
>
> For convenience, a coroutine object should contextually convert to bool=
=20
> with the result being state =3D=3D terminal.
>
> When suspending, a coroutine should be able to return by reference or by=
=20
> value. Different FSM transitions may in general produce different output=
=20
> value types, although in most cases return values are homogeneous. I=20
> propose that return statements produce output values, and that the rules=
=20
> for return type deduction be relaxed. If a resumable lambda is declared=
=20
> with a (trailing, non-placeholder) return type, then it always generates=
=20
> that type. Otherwise, all return statements are deduced separately (the=
=20
> default return type being auto, i.e. by value), subject to the=20
> constraints below.
>
> Suspension comprises returning an output and awaiting further input, and=
=20
> termination is the same except without any await. There needs to be some=
=20
> interaction between a return statement and a subsequent await statement,=
=20
> with some constraints:
>
>    - Several transitions may lead to or from the same state.
>    - Execution must stop at the return or the await, whichever comes last=
..
>    - Each transition has a particular return type, suggesting constraints=
=20
>    on the return statements.
>    - An observable state of the FSM may signal a different return type.
>    - A coroutine may not jump into its own state transition.
>
>
> These constraints are difficult to satisfy, but here=E2=80=99s what I hav=
e so far.
>
>    - An await statement shall be preceded immediately by a return=20
>    statement, not considering enclosing selection or iteration statements=
=20
>    if-else, for, while, do, and switch (note, break cannot precede await)=
..=20
>    Any intervening conditions are evaluated. If control is not transferre=
d to=20
>    an await statement, the next state is terminal (and control is=20
>    returned immediately to the caller).
>    - A return statement may be augmented with a compound statement, which=
=20
>    is executed after the return value expression is evaluated. This preve=
nts=20
>    contortions to refactor computations before the return statement or in=
side=20
>    the conditions.
>    - If a return statement compound statement is exited by a=20
>    jump statement (continue or goto), any await statement(s) at the=20
>    target location may be executed. However, those await statements still=
 must=20
>    be preceded by a return. (This incidentally prevents break from=20
>    working.)
>    - A jump statement inside a return statement shall potentially lead to=
=20
>    an await. Any other jump statement shall not.
>    - return* expression *continue; is shorthand for return* expression *{=
=20
>    continue; }. return *expression* goto *label*; is shorthand for return
>    * expression *{ goto *label*; }.
>    - All unlabeled await statements reachable from a particular return=20
>    statement shall have identical parameter types. These form a=20
>    *state-subset*.
>    - All return statements reachable from a particular state-subset or=20
>    labeled await statement shall have the same return type.
>    - Labeled await statements are assigned to state-subsets by=20
>    partitioning all states according to input (await parameter) and=20
>    output (return expression) types.
>    - All states of a state-subset are implemented by a member function=20
>    with the corresponding signature. When two states would differ only by=
 the=20
>    output (return) type, the member function is a template taking a non-t=
ype=20
>    parameter of states type. Any of the constituent states of a set=20
>    selects the same implementation. The primary template is defined as=20
>    deleted. (The user will seldom need this, so omitting the template arg=
ument=20
>    should produce a diagnostic mentioning the variant return types.)
>
>
> This approach easily allows several awaits to follow a return,=20
> corresponding to diverging FSM paths. Its treatment of loops models FSM=
=20
> cycles. Converging cyclic FSM paths from several returns back to one awai=
t=20
> is easily done with continue. More random patterns require goto, but=20
> there are few use cases and such use of goto should actually reflect=20
> current practices pretty well: it=E2=80=99s not unintuitive that a state =
machine=20
> should goto a state.
>
> For generators, an initial return statement is required to advance past=
=20
> the initial state, to either the generative state or the terminal state.=
=20
> Without this, there is no representation of the empty sequence.
>
> auto accumulate_proto =3D [] ( int max ) resumable {
> // initial:
>     return; // Leave initial state.
>
>     for ( int i =3D 0; // Initialization occurs before transition.
>             i < max; // Comparison occurs before every suspension to=20
> generative state.
>             ) {
>     generative:
>         await ( int addend ) {
>             return i +=3D addend continue;
>         }
>     }
>     // This is unreachable.
> }; // Construct copyable object.
>
> auto countup0 =3D countup;
> assert ( countup0.state =3D=3D countup.initial );
> countup0( 0 ); // Initialize FSM.
> assert ( countup0.state =3D=3D countup.terminal );
>
> auto countup3 =3D countup;
> assert ( countup3.state =3D=3D countup.initial );
> countup3( 3 ); // Initialize FSM.
> assert ( countup3.state =3D=3D countup.generative );
> assert ( countup3( 1 ) =3D=3D 1 );
> assert ( countup3( 2 ) =3D=3D 3 );
> assert ( countup3.state =3D=3D countup.terminal );
>
> The unreachability at the end and the difficulty of appending another=20
> sequence to the end of the generator seem to be weaknesses, so the design=
=20
> space might need more exploration. However, idiomatic safety with empty=
=20
> sequences in the common case is pretty important. Without the initial=20
> return, the initial await is invalid. The extra call for FSM=20
> initialization can be eliminated by jumping over the initial return and=
=20
> into the loop body with goto, but users generally shouldn=E2=80=99t do so=
..
>
> Finally, it is sometimes useful to suspend a coroutine upon an exception=
=20
> instead of to terminate. There may be a try await statement, which does=
=20
> not behave as await statements above, except that if it is labeled, the=
=20
> label is added as a state enumerator. This statement behaves like a norma=
l=20
> try block, except that a suspension point precedes it, and there may be=
=20
> no catch blocks after it. The coroutine is suspended before any exception=
=20
> would propagate out of it (or its catch blocks, if any). Unwinding=20
> continues with the caller.
>
>

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_365_1750394973.1414645224865
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Interesting angle. I did not fully absorbed&nbsp;your=
 proposal, so i cannot comment on its detail&nbsp;yet.</div><div><br></div>=
<div>But I have a comment on methodology of developing generic abstractions=
 suggested by Stepanov.</div><div><br></div><div>(Me paraphrasing, I don't =
even remember which lecture / paper he described it)</div><div><br></div><d=
iv>Start from the best solution to a given problem on a given platform, try=
 to discern the abstraction that can make that pattern easily and safely re=
peatable.</div><div>Apply your abstraction to the problem you derived it fr=
om. Is it an improvement? No perf regression? Good. Now try to apply it to =
some other problem which looks similar.</div><div>Keep iterating until you =
are satisfied.</div><div><br></div><div>For N4134 (and I think N4244 as wel=
l), the primary problem to solve was capturing the best patterns of efficie=
nt async programs (interacting state machines where async completions drive=
 the state machines) and capture the pattern in the coroutine.</div><div>Gi=
ven that abstraction apply it to something else, generators, for example.</=
div><div><br></div><div>Note, it was not meant to be a general purpose stat=
e machine abstraction. It was targeting specific kind of state machines tha=
t can be represented as a coroutine.</div><div><br></div><div>Gor</div><div=
><br></div><div>for await (x: S) { bla } statement. I think it is something=
 that </div><div><br></div><div><br><br>On Wednesday, October 29, 2014 1:06=
:32 AM UTC-7, David Krauss wrote:</div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0px 0px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb=
(204, 204, 204); border-left-width: 1px; border-left-style: solid;"><div st=
yle=3D"-ms-word-wrap: break-word;">I=E2=80=99ve been thinking about corouti=
nes over the past week, while I was offline on vacation. I just want to sha=
re these ideas as incremental contributions.<div><br></div><div>Coroutines =
are similar to finite-state machines, and the C-legacy, switch-based idioms=
 for the two patterns have a lot of overlap. Rather than extrapolate from u=
se cases of coroutines (generators, consumers), we should leverage general =
FSM principles to maximize expressiveness.</div><div><br></div><div>An FSM =
is defined by a set of states including an initial and perhaps a terminal s=
tate, conditions which lead from one state to another depending on input va=
lues, and output values and actions which are taken upon a transition or up=
on reaching a state.</div><div><br></div><div>I propose mapping these essen=
tial properties to C++:</div><div><ul><li>states =3D&gt; suspension point s=
tatements</li><li>transitions =3D&gt; function calls on the coroutine funct=
or</li><li>input values =3D&gt; parameter/argument lists</li><li>output val=
ues =3D&gt; return values</li><li>actions =3D&gt; statements in function bo=
dy</li><li>initial state =3D&gt; coroutine object construction</li><li>term=
inal state =3D&gt; function scope exit</li></ul><div><br></div></div><div>T=
his mapping should resolve various issues such as:</div><div><ul><li>Yielde=
d-object aliasing, which has been raised the thread =E2=80=9Ccomment on n42=
44=E2=80=9D on this list.</li><li>The potential to pass zero or several val=
ues to a coroutine before resuming it, or to yield zero or several values b=
efore suspending. These possibilities add either UB or runtime check overhe=
ad.</li><li>Common errors such as forgetting to explicitly specify or query=
 initial and final states. Such errors have appeared in examples in the oth=
er thread (=E2=80=9Cwriting simple generators,=E2=80=9D which appears in a =
message in the thread =E2=80=9CComment on N4244=E2=80=9D with capitalizatio=
n).</li></ul></div><div><br></div><div>Subexpressions like <font face=3D"Co=
urier">await</font> or <font face=3D"Courier">yield from</font> are a poor =
way to receive input values because subexpression evaluation is unsequenced=
, so it makes no sense to have more than one such subexpression in a full-e=
xpression. Also it causes the suspension point to be indeterminately sequen=
ced with side effects of the full-expression that do not depend on it. Fina=
lly, there may be constraints on the location of suspension points, such as=
 the provision in N4134 that exception handling cannot be suspended.</div><=
div><br></div><div>Suspension points should have:</div><div><ul><li>clear s=
equencing</li><li>ability to receive arbitrary new values</li><li>easily-id=
entifiable context relative to surrounding statements</li><li>ability to ex=
ternally identify the state</li></ul></div><div>These constraints point tow=
ard an <font face=3D"Courier">await</font> statement:</div><div><br></div><=
div><font face=3D"Courier">await</font> <font face=3D"Courier">(</font> <i>=
parameter-declaration-clause</i> <font face=3D"Courier">)</font>&nbsp;<i>st=
atement</i></div><div><br></div><div>To identify the states, a coroutine ob=
ject has an unscoped member enumeration&nbsp;<font face=3D"Courier">states<=
/font> and a nonstatic member named <font face=3D"Courier">state</font>. Ea=
ch&nbsp;<span style=3D"font-family: Courier;">await</span>&nbsp;statement w=
hich is labeled adds its label as an enumerator. (The enumeration values ar=
e unspecified. The standard should not guarantee portability of state value=
s across builds of the same program.) The standard may reserve <font face=
=3D"Courier">initial</font>,&nbsp;<font face=3D"Courier">terminal</font>,&n=
bsp;<span style=3D"font-family: Courier;">state</span>, and <font face=3D"C=
ourier">states</font> as label identifiers within coroutines. It would be p=
referable to have a scoped enumeration, but using it would require naming t=
he closure type, which is difficult. Some extension to scoped enumerations =
could alleviate this issue.</div><div><br></div><div>For convenience, a cor=
outine object should contextually convert to <font face=3D"Courier">bool</f=
ont> with the result being <font face=3D"Courier">state =3D=3D terminal</fo=
nt>.</div><div><br></div><div>When suspending, a coroutine should be able t=
o return by reference or by value. Different FSM transitions may in general=
 produce different output value types, although in most cases return values=
 are homogeneous. I propose that return statements produce output values, a=
nd that the rules for return type deduction be relaxed. If a resumable lamb=
da is declared with a (trailing, non-placeholder) return type, then it alwa=
ys generates that type. Otherwise, all return statements are deduced separa=
tely (the default return type being&nbsp;<font face=3D"Courier">auto</font>=
, i.e. by value), subject to the constraints below.</div><div><br></div><di=
v>Suspension comprises returning an output and awaiting further input, and =
termination is the same except without any await. There needs to be some in=
teraction between a <font face=3D"Courier">return</font> statement and a su=
bsequent <font face=3D"Courier">await</font> statement, with some constrain=
ts:</div><div><ul><li>Several transitions may lead to or from the same stat=
e.</li><li>Execution must stop at the <font face=3D"Courier">return</font> =
or the <font face=3D"Courier">await</font>, whichever comes last.</li><li>E=
ach transition has a particular return type, suggesting constraints on the =
return statements.</li><li>An observable state of the FSM may signal a diff=
erent return type.</li><li>A coroutine may not jump into its own state tran=
sition.</li></ul></div><div><br></div><div>These constraints are difficult =
to satisfy, but here=E2=80=99s what I have so far.</div><div><ul><li>An <fo=
nt face=3D"Courier">await</font> statement shall be preceded immediately by=
 a <font face=3D"Courier">return</font> statement, not considering enclosin=
g selection or iteration statements <font face=3D"Courier">if</font>-<font =
face=3D"Courier">else</font>,&nbsp;<font face=3D"Courier">for</font>, <font=
 face=3D"Courier">while</font>, <font face=3D"Courier">do</font>, and&nbsp;=
<font face=3D"Courier">switch</font> (note,&nbsp;<font face=3D"Courier">bre=
ak</font> cannot precede <font face=3D"Courier">await</font>). Any interven=
ing conditions are evaluated. If control is not transferred to an <font fac=
e=3D"Courier">await</font> statement, the next state is <font face=3D"Couri=
er">terminal</font>&nbsp;(and control is returned immediately to the caller=
).</li><li>A <font face=3D"Courier">return</font> statement may be augmente=
d with a compound statement, which is executed after the return value expre=
ssion is evaluated. This prevents contortions to refactor computations befo=
re the return statement or inside the conditions.</li><li>If a <font face=
=3D"Courier">return</font> statement compound statement is exited by a jump=
&nbsp;statement (<font face=3D"Courier">continue</font>&nbsp;or&nbsp;<font =
face=3D"Courier">goto</font>), any <font face=3D"Courier">await</font> stat=
ement(s) at the target location may be executed. However, those await state=
ments still must be preceded by a return. (This incidentally prevents&nbsp;=
<span style=3D"font-family: Courier;">break</span>&nbsp;from working.)</li>=
<li>A jump statement inside a <font face=3D"Courier">return</font> statemen=
t shall potentially lead to an <font face=3D"Courier">await</font>. Any oth=
er jump statement shall not.</li><li><font face=3D"Courier">return</font><i=
> expression </i><font face=3D"Courier">continue;</font> is shorthand for <=
font face=3D"Courier">return<i style=3D"font-family: Helvetica;">&nbsp;expr=
ession&nbsp;</i>{ continue; }</font>. <font face=3D"Courier">return</font> =
<i>expression</i> <font face=3D"Courier">goto</font> <i>label</i><font face=
=3D"Courier">;</font> is shorthand for&nbsp;<span style=3D"font-family: Cou=
rier;">return</span><i>&nbsp;expression&nbsp;</i><span style=3D"font-family=
: Courier;">{&nbsp;<font face=3D"Courier">goto</font><span style=3D"font-fa=
mily: Helvetica;">&nbsp;</span><i style=3D"font-family: Helvetica;">l<wbr>a=
bel</i>; }</span>.</li><li>All unlabeled&nbsp;<font face=3D"Courier">await<=
/font> statements reachable from a particular <font face=3D"Courier">return=
</font> statement shall have identical parameter types. These form a <i>sta=
te-subset</i>.</li><li>All <font face=3D"Courier">return</font> statements =
reachable from a particular state-subset or labeled <font face=3D"Courier">=
await</font> statement shall have the same return type.</li><li>Labeled <fo=
nt face=3D"Courier">await</font> statements are assigned to state-subsets b=
y partitioning all states according to input (<font face=3D"Courier">await<=
/font> parameter) and output (<font face=3D"Courier">return</font> expressi=
on) types.</li><li>All states of a state-subset are implemented by a member=
 function with the corresponding signature. When two states would differ on=
ly by the output (return) type, the member function is a template taking a =
non-type parameter of <font face=3D"Courier">states</font> type. Any of the=
 constituent states of a set selects the same implementation. The primary t=
emplate is defined as deleted. (The user will seldom need this, so omitting=
 the template argument should produce a diagnostic mentioning the variant r=
eturn types.)</li></ul></div><div><br></div><div>This approach easily allow=
s several <font face=3D"Courier">await</font>s to follow a <font face=3D"Co=
urier">return</font>, corresponding to diverging FSM paths. Its treatment o=
f loops models FSM cycles. Converging cyclic FSM paths from several <font f=
ace=3D"Courier">returns</font>&nbsp;back to one <font face=3D"Courier">awai=
t</font> is easily done with <font face=3D"Courier">continue</font>. More r=
andom patterns require&nbsp;<font face=3D"Courier">goto</font>, but there a=
re few use cases and such use of <font face=3D"Courier">goto</font> should =
actually reflect current practices pretty well: it=E2=80=99s not unintuitiv=
e that a state machine should <font face=3D"Courier">goto</font> a state.</=
div><div><br></div><div>For generators, an initial return statement is requ=
ired to advance past the initial state, to either the generative state or t=
he terminal state. Without this, there is no representation of the empty se=
quence.</div><div><br></div><div><div><font face=3D"Courier">auto accumulat=
e_proto =3D [] ( int max ) resumable {</font></div><div><font face=3D"Couri=
er">// initial:</font></div><div><font face=3D"Courier">&nbsp; &nbsp; retur=
n; // Leave initial state.</font></div><div><font face=3D"Courier"><br></fo=
nt></div><div><font face=3D"Courier">&nbsp; &nbsp; for ( int i =3D 0; // In=
itialization occurs before transition.</font></div><div><font face=3D"Couri=
er">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i &lt; max; // Comparison occ=
urs before every suspension to generative state.</font></div><div><font fac=
e=3D"Courier">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) {</font><div><fon=
t face=3D"Courier">&nbsp; &nbsp; generative:</font></div><div><font face=3D=
"Courier">&nbsp; &nbsp; &nbsp; &nbsp; await ( int addend ) {</font></div><d=
iv><span style=3D"font-family: Courier;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;=
 &nbsp; return i +=3D addend continue;</span></div><div><span style=3D"font=
-family: Courier;">&nbsp; &nbsp; &nbsp; &nbsp; }</span></div><div><span sty=
le=3D"font-family: Courier;">&nbsp; &nbsp; }</span></div></div></div><div><=
span style=3D"font-family: Courier;">&nbsp; &nbsp; // This is unreachable.<=
/span></div><div><span style=3D"font-family: Courier;">}; // Construct copy=
able object.</span></div><div><span style=3D"font-family: Courier;"><br></s=
pan></div><div><span style=3D"font-family: Courier;">auto countup0 =3D coun=
tup;</span></div><div><div><font face=3D"Courier">assert ( countup0.state =
=3D=3D&nbsp;countup.initial );</font></div><div></div></div><div><span styl=
e=3D"font-family: Courier;">countup0( 0 ); // Initialize FSM.</span></div><=
div><div><font face=3D"Courier">assert ( countup0.state =3D=3D&nbsp;countup=
..terminal );</font></div><div></div></div><div><span style=3D"font-family: =
Courier;"><br></span></div><div><span style=3D"font-family: Courier;">auto =
countup3 =3D countup;</span></div><div><div><font face=3D"Courier">assert (=
 countup3.state =3D=3D&nbsp;countup.initial );</font></div><div></div></div=
><div><span style=3D"font-family: Courier;">countup3( 3 );</span><span styl=
e=3D"font-family: Courier;">&nbsp;</span><span style=3D"font-family: Courie=
r;">// Initialize FSM.</span></div><div><font face=3D"Courier">assert ( cou=
ntup3.state =3D=3D&nbsp;countup.generative );</font></div><div><font face=
=3D"Courier">assert ( countup3( 1 ) =3D=3D 1 );</font></div><div><font face=
=3D"Courier">assert ( countup3( 2 ) =3D=3D 3 );</font></div><div><div><div>=
<div><font face=3D"Courier">assert ( countup3.state =3D=3D&nbsp;countup.ter=
minal );</font></div><div><font face=3D"Courier"><br></font></div><div></di=
v></div></div></div><div>The unreachability at the end and the difficulty o=
f appending another sequence to the end of the generator seem to be weaknes=
ses, so the design space might need more exploration. However, idiomatic sa=
fety with empty sequences in the common case is pretty important. Without t=
he initial <font face=3D"Courier">return</font>, the initial <font face=3D"=
Courier">await</font> is invalid. The extra call for FSM initialization can=
 be eliminated by jumping over the initial return and into the loop body wi=
th <font face=3D"Courier">goto</font>, but users generally shouldn=E2=80=99=
t do so.</div><div><br></div><div>Finally, it is sometimes useful to suspen=
d a coroutine upon an exception instead of to terminate. There may be a&nbs=
p;<font face=3D"Courier">try await</font> statement, which does not behave =
as <font face=3D"Courier">await</font> statements above, except that if it =
is labeled, the label is added as a state enumerator. This statement behave=
s like a normal <font face=3D"Courier">try</font> block, except that a susp=
ension point precedes it, and there may be no <font face=3D"Courier">catch<=
/font> blocks after it. The coroutine is suspended before any exception wou=
ld propagate out of it (or its catch blocks, if any). Unwinding continues w=
ith the caller.</div><div><br></div></div></blockquote></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_365_1750394973.1414645224865--

.


Author: Gor Nishanov <gornishanov@gmail.com>
Date: Wed, 29 Oct 2014 22:03:28 -0700 (PDT)
Raw View
------=_Part_362_1677940593.1414645408164
Content-Type: text/plain; charset=UTF-8

ignore the half completed sentence after "Gor"

--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposals/.

------=_Part_362_1677940593.1414645408164
Content-Type: text/html; charset=UTF-8

<div dir="ltr"><div>ignore the&nbsp;half completed sentence after "Gor"</div></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an email to <a href="mailto:std-proposals+unsubscribe@isocpp.org">std-proposals+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href="mailto:std-proposals@isocpp.org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href="http://groups.google.com/a/isocpp.org/group/std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/</a>.<br />

------=_Part_362_1677940593.1414645408164--

.


Author: David Krauss <potswa@gmail.com>
Date: Thu, 30 Oct 2014 13:48:04 +0800
Raw View
On 2014=E2=80=9310=E2=80=9330, at 1:00 PM, Gor Nishanov <gornishanov@gmail.=
com> wrote:

> Interesting angle. I did not fully absorbed your proposal, so i cannot co=
mment on its detail yet.

It=E2=80=99s not a complete proposal, just half-digested bits and pieces th=
at I hope might catch some interest, especially from implementers. I spent =
a week away from the computer, and those are my notes after returning befor=
e I switched gears back to my own proposals.

> But I have a comment on methodology of developing generic abstractions su=
ggested by Stepanov.
>=20
> (Me paraphrasing, I don't even remember which lecture / paper he describe=
d it)
>=20
> Start from the best solution to a given problem on a given platform, try =
to discern the abstraction that can make that pattern easily and safely rep=
eatable.
> Apply your abstraction to the problem you derived it from. Is it an impro=
vement? No perf regression? Good. Now try to apply it to some other problem=
 which looks similar.
> Keep iterating until you are satisfied.

Yep!

N4134 and N4244 are based on working prototypes designed to solve immediate=
 problems. My suggestions are likely to make implementation less expedient,=
 but I think performance and safety can be (re)gained.

Coroutines/FSMs are useful for all kinds of protocols, whether or not imple=
mented through async I/O. Text parsers and GUIs are also amenable. (Perform=
ance is a non-issue for GUIs, though, except perhaps when it=E2=80=99s a se=
rver-side program, in which case you again have an async network protocol.)

> For N4134 (and I think N4244 as well), the primary problem to solve was c=
apturing the best patterns of efficient async programs (interacting state m=
achines where async completions drive the state machines) and capture the p=
attern in the coroutine.
> Given that abstraction apply it to something else, generators, for exampl=
e.
>=20
> Note, it was not meant to be a general purpose state machine abstraction.=
 It was targeting specific kind of state machines that can be represented a=
s a coroutine.

Yeah. Whether all FSMs are covered depends on the existence of some mathema=
tical proof, which I=E2=80=99ve not done. I only outlined a paradigm and de=
sign strategy which is unlikely to leak any FSMs. But I think N4134 and N42=
44 do have them covered already.

Mainly I=E2=80=99m suggesting to tighten things up a bit, without losing an=
y existing expressiveness. Hopefully at least some of my ideas can be adopt=
ed without total rewrites. But in any case, it=E2=80=99s good to at least d=
iscuss an idealized model so as to see and navigate the big picture. There=
=E2=80=99s still time to revise things, I don=E2=80=99t suppose the current=
 choice is only between the current prototypes.

Unfortunately I have a lot of proposals of my own, which I=E2=80=99m suppos=
ed to be reviewing and making slides for, and I don=E2=80=99t know how much=
 more time I can spend on coroutines. I will try to visit SG1 at Urbana.

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

.


Author: Gor Nishanov <gornishanov@gmail.com>
Date: Thu, 30 Oct 2014 06:18:57 -0700 (PDT)
Raw View
------=_Part_687_1619066570.1414675137720
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable



On Wednesday, October 29, 2014 10:48:15 PM UTC-7, David Krauss wrote:
>
>
> On 2014=E2=80=9310=E2=80=9330, at 1:00 PM, Gor Nishanov <gorni...@gmail.c=
om <javascript:>>=20
> wrote:=20
>
> > Start from the best solution to a given problem on a given platform, tr=
y=20
> to discern the abstraction that can make that pattern easily and safely=
=20
> repeatable.=20
> > Apply your abstraction to the problem you derived it from. Is it an=20
> improvement? No perf regression? Good. Now try to apply it to some other=
=20
> problem which looks similar.=20
> > Keep iterating until you are satisfied.=20
>
> Yep!=20
>
> N4134 and N4244 are based on working prototypes designed to solve=20
> immediate problems. My suggestions are likely to make implementation less=
=20
> expedient, but I think performance and safety can be (re)gained.=20
>

My suggestion was not to start with theory, but, come up with some real=20
complicated problem that is currently difficult to write and requires a lot=
=20
of code.
Imagine, how your improvement to N4134 / N4244 can help capture the pattern=
=20
of that problem.

Some state machines can be easily mapped to coroutines (where number of=20
different events arriving at every state is small 1 or 2), others might not=
=20
look much better than what you can do with the switch yourself.
=20
>>  I will try to visit SG1 at Urbana.

Cool. See you there.

Gor

--=20

---=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
Visit this group at http://groups.google.com/a/isocpp.org/group/std-proposa=
ls/.

------=_Part_687_1619066570.1414675137720
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><br><br>On Wednesday, October 29, 2014 10:48:15 PM UTC-7, =
David Krauss wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0px 0=
px 0px 0.8ex; padding-left: 1ex; border-left-color: rgb(204, 204, 204); bor=
der-left-width: 1px; border-left-style: solid;">
<br>On 2014=E2=80=9310=E2=80=9330, at 1:00 PM, Gor Nishanov &lt;<a onmoused=
own=3D"this.href=3D'javascript:';return true;" onclick=3D"this.href=3D'java=
script:';return true;" href=3D"javascript:" target=3D"_blank" gdf-obfuscate=
d-mailto=3D"SySrydjV_E8J">gorni...@gmail.com</a>&gt; wrote:
<br>
<br>&gt; Start from the best solution to a given problem on a given platfor=
m, try to discern the abstraction that can make that pattern easily and saf=
ely repeatable.
<br>&gt; Apply your abstraction to the problem you derived it from. Is it a=
n improvement? No perf regression? Good. Now try to apply it to some other =
problem which looks similar.
<br>&gt; Keep iterating until you are satisfied.
<br>
<br>Yep!
<br>
<br>N4134 and N4244 are based on working prototypes designed to solve immed=
iate problems. My suggestions are likely to make implementation less expedi=
ent, but I think performance and safety can be (re)gained.
<br></blockquote><div><br></div><div>My&nbsp;suggestion was not to start wi=
th theory, but, come up with some real complicated problem that is currentl=
y difficult to write and requires a lot of code.</div><div>Imagine, how you=
r improvement to N4134 / N4244 can help capture the pattern of that problem=
..</div><div><br></div><div>Some state machines can be easily mapped to coro=
utines (where number of different events arriving at every state is small 1=
 or 2), others might not look much better than what you can do with the swi=
tch yourself.</div><div>&nbsp;<br>&gt;&gt;&nbsp; I will try to visit SG1 at=
 Urbana.</div><div><br></div><div>Cool. See you there.</div><div><br>Gor</d=
iv></div>

<p></p>

-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals&quot; group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
Visit this group at <a href=3D"http://groups.google.com/a/isocpp.org/group/=
std-proposals/">http://groups.google.com/a/isocpp.org/group/std-proposals/<=
/a>.<br />

------=_Part_687_1619066570.1414675137720--

.