Topic: More features for resumable lambdas (N4244)
Author: David Krauss <potswa@gmail.com>
Date: Sat, 18 Oct 2014 07:41:50 +0800
Raw View
--Apple-Mail=_51475623-EE18-4F42-9ADB-F2BB41140814
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
N4244 is a great approach to coroutines, but it's hard to find one size tha=
t fits all. I recently tackled the problem in my own project, and got stuck=
until I realized that I needed to use two separate coroutine libraries sim=
ultaneously. N4244 includes aspects of both the libraries I created but wou=
ld replace neither. It could perhaps be made a bit (even) more flexible in =
these directions:
1. Update the state when strictly needed. The state updates are only shown =
in the demonstration code, but sometimes there are several between exit poi=
nts. A new state only needs to be written when reentry is actually possible=
..
2. Yield the yield keyword. The return keyword can implement yield, and onl=
y send the coroutine to the terminal state when it's the last statement in =
the function body.
3. Support exceptions. It's nice to suspend a stack of coroutines on an exc=
eption, and resume the entire stack. When an exception unwinds a coroutine,=
it should update its state. This behavior would be uniform with the above =
suggestion for return: any time a coroutine is exited, it is left ready to =
restart.
The re-entry point saved by an exception is the (beginning of the) statemen=
t which threw it. Yes, writing such code is tricky, but it's worth it.
4. Recursion specifications. There should be specified undefined behavior w=
hen a single object is asked to generate two stack frames. Most of the acti=
vation record is contained in the lambda object, but unless the return addr=
ess is also in there, restarting the function will still consume a little s=
tack. Note that the physical location of stack frames is often considered t=
o be a security issue.
Likewise, the proposal says, "This allows us to copy them freely like other=
value-based types, with the additional behaviour that when we copy them we=
also copy the yield point at which they are currently suspended," but this=
presumes that the coroutine is suspended at all. A coroutine which tries t=
o manipulate itself is usually asking for trouble.
However, it can be safe and useful to save a copy before entering the termi=
nal state. This needs more investigation.
5. Serialization. This probably can only be a future direction, pending ref=
lection capabilities, but a server with a million connections should have t=
he ability to restart them after a failure. Resumable lambdas shouldn't be =
bound to virtual memory.
---
Unfortunately, some of this problem got paged out of my brain cells, since =
I put it aside to spend the past month preparing for the Urbana meeting. Ir=
onic! I might have more or different ideas later.
--=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=_51475623-EE18-4F42-9ADB-F2BB41140814
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;">N4244 is a great appro=
ach to coroutines, but it’s hard to find one size that fits all. I re=
cently tackled the problem in my own project, and got stuck until I realize=
d that I needed to use two separate coroutine libraries simultaneously. N42=
44 includes aspects of both the libraries I created but would replace neith=
er. It could perhaps be made a bit (even) more flexible in these directions=
:<div><br></div><div>1. Update the state when strictly needed. The state up=
dates are only shown in the demonstration code, but sometimes there are sev=
eral between exit points. A new state only needs to be written when reentry=
is actually possible.</div><div><br></div><div>2. Yield the <font fac=
e=3D"Courier">yield</font> keyword. The <font face=3D"Courier">re=
turn</font> keyword can implement <font face=3D"Courier">yield</f=
ont>, and only send the coroutine to the terminal state when it’s the=
last statement in the function body.</div><div><br></div><div>3. Support e=
xceptions. It’s nice to suspend a stack of coroutines on an exception=
, and resume the entire stack. When an exception unwinds a coroutine, it sh=
ould update its state. This behavior would be uniform with the above sugges=
tion for <font face=3D"Courier">return</font>: any time a coroutine is=
exited, it is left ready to restart.</div><div><br></div><div>The re-entry=
point saved by an exception is the (beginning of the) statement which thre=
w it. Yes, writing such code is tricky, but it’s worth it.</div><div>=
<br></div><div>4. Recursion specifications. There should be specified undef=
ined behavior when a single object is asked to generate two stack frames. M=
ost of the activation record is contained in the lambda object, but unless =
the return address is also in there, restarting the function will still con=
sume a little stack. Note that the physical location of stack frames is oft=
en considered to be a security issue.</div><div><br></div><div>Likewise, th=
e proposal says, "This allows us to copy them freely like other value-based=
types, with the additional behaviour that when we copy them we also c=
opy the yield point at which they are currently suspended,”=
but this presumes that the coroutine is suspended at all. A coroutine whic=
h tries to manipulate itself is usually asking for trouble.</div><div><br><=
/div><div>However, it can be safe and useful to save a copy before entering=
the terminal state. This needs more investigation.</div><div><br></div><di=
v>5. Serialization. This probably can only be a future direction, pending r=
eflection capabilities, but a server with a million connections should have=
the ability to restart them after a failure. Resumable lambdas shouldn&rsq=
uo;t be bound to virtual memory.</div><div><br></div><div>––&nd=
ash;</div><div>Unfortunately, some of this problem got paged out of my brai=
n cells, since I put it aside to spend the past month preparing for the Urb=
ana meeting. Ironic! I might have more or different ideas later.</div></bod=
y></html>
<p></p>
-- <br />
<br />
--- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" 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=_51475623-EE18-4F42-9ADB-F2BB41140814--
.
Author: chris.kohlhoff@gmail.com
Date: Fri, 17 Oct 2014 22:40:47 -0700 (PDT)
Raw View
------=_Part_1544_1288480173.1413610847656
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hi David,
On Saturday, October 18, 2014 10:42:05 AM UTC+11, David Krauss wrote:
>
> N4244 is a great approach to coroutines, but it=E2=80=99s hard to find on=
e size=20
> that fits all. I recently tackled the problem in my own project, and got=
=20
> stuck until I realized that I needed to use two separate coroutine=20
> libraries simultaneously. N4244 includes aspects of both the libraries I=
=20
> created but would replace neither. It could perhaps be made a bit (even)=
=20
> more flexible in these directions:
>
> 1. Update the state when strictly needed. The state updates are only show=
n=20
> in the demonstration code, but sometimes there are several between exit=
=20
> points. A new state only needs to be written when reentry is actually=20
> possible.
>
The state is updated for "yield" and "unwind" points, so I assume you are=
=20
referring to the "unwind" points. Since the locals are implemented using=20
data members we need to keep track of which ones have been constructed in=
=20
order to run their destructors. Updating the state may not be the only way=
=20
of accomplishing this, but that is why the demonstration code does this.
=20
> 2. Yield the yield keyword. The return keyword can implement yield, and=
=20
> only send the coroutine to the terminal state when it=E2=80=99s the last =
statement=20
> in the function body.
>
Are you a proponent of the single-entry-single-exit programming style? :)=
=20
In normal functions we can have early return, so distinguishing return from=
=20
yield mirrors this.
3. Support exceptions. It=E2=80=99s nice to suspend a stack of coroutines o=
n an=20
> exception, and resume the entire stack. When an exception unwinds a=20
> coroutine, it should update its state. This behavior would be uniform wit=
h=20
> the above suggestion for return: any time a coroutine is exited, it is=20
> left ready to restart.
>
This sounds like an interesting idea, but I'd like to understand the=20
context. Can you please explain the use cases for this? Right now an=20
exception will put the coroutine into the terminal state, to mirror what=20
happens in a normal function.
The re-entry point saved by an exception is the (beginning of the)=20
> statement which threw it. Yes, writing such code is tricky, but it=E2=80=
=99s worth=20
> it.
>
N.B. with the design as it is now, you can at least write "yield throw x;"=
=20
to get this behaviour.
=20
> 4. Recursion specifications. There should be specified undefined behavior=
=20
> when a single object is asked to generate two stack frames. Most of the=
=20
> activation record is contained in the lambda object, but unless the retur=
n=20
> address is also in there, restarting the function will still consume a=20
> little stack. Note that the physical location of stack frames is often=20
> considered to be a security issue.
>
You're probably right about restricting recursive calls. I will think about=
=20
this.
Likewise, the proposal says, "This allows us to copy them freely like other=
=20
> value-based types, with the additional behaviour that when we copy them w=
e=20
> also copy the yield point at which they are currently suspended,=E2=80=9D=
but this=20
> presumes that the coroutine is suspended at all. A coroutine which tries =
to=20
> manipulate itself is usually asking for trouble.=20
>
However, it can be safe and useful to save a copy before entering the=20
> terminal state. This needs more investigation.
>
=20
You're correct that the behaviour of copying in between yields should be=20
described, since in the proposal you do have the ability to copy via=20
[]this.=20
5. Serialization. This probably can only be a future direction, pending=20
> reflection capabilities, but a server with a million connections should=
=20
> have the ability to restart them after a failure. Resumable lambdas=20
> shouldn=E2=80=99t be bound to virtual memory.
>
You are not the only one to suggest this... I have had someone ask about=20
sending them over a network too. It seems feasible to do this with=20
reflection support.
Cheers,
Chris
--=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_1544_1288480173.1413610847656
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hi David,<br><br>On Saturday, October 18, 2014 10:42:05 AM=
UTC+11, David Krauss wrote:<blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><d=
iv style=3D"word-wrap:break-word">N4244 is a great approach to coroutines, =
but it=E2=80=99s hard to find one size that fits all. I recently tackled th=
e problem in my own project, and got stuck until I realized that I needed t=
o use two separate coroutine libraries simultaneously. N4244 includes aspec=
ts of both the libraries I created but would replace neither. It could perh=
aps be made a bit (even) more flexible in these directions:<div><br></div><=
div>1. Update the state when strictly needed. The state updates are only sh=
own in the demonstration code, but sometimes there are several between exit=
points. A new state only needs to be written when reentry is actually poss=
ible.</div></div></blockquote><div><br></div><div>The state is updated for =
"yield" and "unwind" points, so I assume you are referring to the "unwind" =
points. Since the locals are implemented using data members we need to keep=
track of which ones have been constructed in order to run their destructor=
s. Updating the state may not be the only way of accomplishing this, but th=
at is why the demonstration code does this.</div><div> </div><blockquo=
te class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left:=
1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><di=
v>2. Yield the <font face=3D"Courier">yield</font> keyword. The&n=
bsp;<font face=3D"Courier">return</font> keyword can implement <f=
ont face=3D"Courier">yield</font>, and only send the coroutine to the termi=
nal state when it=E2=80=99s the last statement in the function body.</div><=
/div></blockquote><div><br></div><div>Are you a proponent of the single-ent=
ry-single-exit programming style? :) In normal functions we can have early =
return, so distinguishing return from yield mirrors this.</div><div><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:bre=
ak-word"><div>3. Support exceptions. It=E2=80=99s nice to suspend a stack o=
f coroutines on an exception, and resume the entire stack. When an exceptio=
n unwinds a coroutine, it should update its state. This behavior would be u=
niform with the above suggestion for <font face=3D"Courier">return</fo=
nt>: any time a coroutine is exited, it is left ready to restart.<br></div>=
</div></blockquote><div><br></div><div>This sounds like an interesting idea=
, but I'd like to understand the context. Can you please explain the use ca=
ses for this? Right now an exception will put the coroutine into the termin=
al state, to mirror what happens in a normal function.</div><div><br></div>=
<blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bor=
der-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-=
word"><div>The re-entry point saved by an exception is the (beginning of th=
e) statement which threw it. Yes, writing such code is tricky, but it=E2=80=
=99s worth it.</div></div></blockquote><div><br></div><div>N.B. with the de=
sign as it is now, you can at least write "yield throw x;" to get this beha=
viour.</div><div> </div><blockquote class=3D"gmail_quote" style=3D"mar=
gin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><=
div style=3D"word-wrap:break-word"><div>4. Recursion specifications. There =
should be specified undefined behavior when a single object is asked to gen=
erate two stack frames. Most of the activation record is contained in the l=
ambda object, but unless the return address is also in there, restarting th=
e function will still consume a little stack. Note that the physical locati=
on of stack frames is often considered to be a security issue.<br></div></d=
iv></blockquote><div><br></div><div>You're probably right about restricting=
recursive calls. I will think about this.</div><div><br></div><blockquote =
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1p=
x #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div>L=
ikewise, the proposal says, "This allows us to copy them freely like other =
value-based types, with the additional behaviour that when we copy the=
m we also copy the yield point at which they are currently suspen=
ded,=E2=80=9D but this presumes that the coroutine is suspended at all. A c=
oroutine which tries to manipulate itself is usually asking for trouble.&nb=
sp;</div></div></blockquote><blockquote class=3D"gmail_quote" style=3D"marg=
in: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><d=
iv style=3D"word-wrap:break-word"><div>However, it can be safe and useful t=
o save a copy before entering the terminal state. This needs more investiga=
tion.</div></div></blockquote><div> </div><div>You're correct that the=
behaviour of copying in between yields should be described, since in the p=
roposal you do have the ability to copy via []this. </div><div><br></d=
iv><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;=
border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:bre=
ak-word"><div>5. Serialization. This probably can only be a future directio=
n, pending reflection capabilities, but a server with a million connections=
should have the ability to restart them after a failure. Resumable lambdas=
shouldn=E2=80=99t be bound to virtual memory.</div></div></blockquote><div=
><br></div><div>You are not the only one to suggest this... I have had some=
one ask about sending them over a network too. It seems feasible to do this=
with reflection support.</div><div><br></div><div>Cheers,</div><div>Chris<=
/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" 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_1544_1288480173.1413610847656--
.
Author: David Krauss <potswa@gmail.com>
Date: Sat, 18 Oct 2014 14:43:38 +0800
Raw View
--Apple-Mail=_580758BA-B414-46AC-BD20-1F453C5CB106
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=ISO-8859-1
On 2014-10-18, at 1:40 PM, chris.kohlhoff@gmail.com wrote:
> The state is updated for "yield" and "unwind" points, so I assume you are=
referring to the "unwind" points. Since the locals are implemented using d=
ata members we need to keep track of which ones have been constructed in or=
der to run their destructors. Updating the state may not be the only way of=
accomplishing this, but that is why the demonstration code does this.
Well, I was just looking at the example at the top of page 15, but really i=
t's not worth mentioning since the choice of update points can be optimized=
by the implementation. Never mind.
Not sure I understand how unwind points come into play. If an exception cro=
sses the coroutine, and leaves it in a state where destruction is the only =
option, then why not just destroy the whole member activation record and en=
ter the terminal state during unwinding? Then the destructor never needs to=
know.
> 2. Yield the yield keyword. The return keyword can implement yield, and o=
nly send the coroutine to the terminal state when it's the last statement i=
n the function body.
>=20
> Are you a proponent of the single-entry-single-exit programming style? :)=
In normal functions we can have early return, so distinguishing return fro=
m yield mirrors this.
I'm actually a vehement opponent, but the point is mostly moot for coroutin=
es.
1. Few coroutines have an early exit anyway. Most loop and exit at the end.
2. There's no difference between yield and return, in the proposed system, =
except for when the user inspects the state. In many cases the state never =
gets inspected.
3. Another, more general, way to express early return would be []this.termi=
nate().
// Status quo
if ( done ) return value;
else yield value;
// Slightly simpler
if ( done ) []this.terminate();
return value;
This style would require return to inspect the state before setting it, but=
that could be optimized out when it's unconditional. Also, it would allow =
differentiating terminal and non-terminal exceptions.
> 3. Support exceptions. It's nice to suspend a stack of coroutines on an e=
xception, and resume the entire stack. When an exception unwinds a coroutin=
e, it should update its state. This behavior would be uniform with the abov=
e suggestion for return: any time a coroutine is exited, it is left ready t=
o restart.
>=20
> This sounds like an interesting idea, but I'd like to understand the cont=
ext. Can you please explain the use cases for this? Right now an exception =
will put the coroutine into the terminal state, to mirror what happens in a=
normal function.
The application is to allow an operation to be restarted after an exception=
.. With serialization, you can resume processing after restarting the proces=
s.
Actually, such "coroutines" don't need yield at all, and it would be reason=
able to want this without containment by a lambda. I don't think wrapping a=
restartable function in a lambda expression should cause much trouble thou=
gh.
> The re-entry point saved by an exception is the (beginning of the) statem=
ent which threw it. Yes, writing such code is tricky, but it's worth it.
>=20
> N.B. with the design as it is now, you can at least write "yield throw x;=
" to get this behavior.
Interesting. Is this restricted to functions of void return type, i.e. a fu=
nction can yield value; or yield throw; but not both?
Why does the yield make a difference? I would think the throw would set the=
state to an unwind point, and yield would not be reached at all.
> 5. Serialization. This probably can only be a future direction, pending r=
eflection capabilities, but a server with a million connections should have=
the ability to restart them after a failure. Resumable lambdas shouldn't b=
e bound to virtual memory.
>=20
> You are not the only one to suggest this... I have had someone ask about =
sending them over a network too. It seems feasible to do this with reflecti=
on support.
I suppose the reflection can already be found if you store everything in tu=
ples.
--=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=_580758BA-B414-46AC-BD20-1F453C5CB106
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=ISO-8859-1
<html><head><meta http-equiv=3D"Content-Type" content=3D"text/html charset=
=3Dwindows-1252"></head><body style=3D"word-wrap: break-word; -webkit-nbsp-=
mode: space; -webkit-line-break: after-white-space;"><br><div><div>On 2014&=
ndash;10–18, at 1:40 PM, <a href=3D"mailto:chris.kohlhoff@gmail.com">=
chris.kohlhoff@gmail.com</a> wrote:</div><br class=3D"Apple-interchange-new=
line"><blockquote type=3D"cite"><div dir=3D"ltr"><div>The state is updated =
for "yield" and "unwind" points, so I assume you are referring to the "unwi=
nd" points. Since the locals are implemented using data members we need to =
keep track of which ones have been constructed in order to run their destru=
ctors. Updating the state may not be the only way of accomplishing this, bu=
t that is why the demonstration code does this.</div></div></blockquote><di=
v><br></div><div>Well, I was just looking at the example at the top of page=
15, but really it’s not worth mentioning since the choice of update =
points can be optimized by the implementation. Never mind.</div><div><br></=
div><div>Not sure I understand how unwind points come into play. If an exce=
ption crosses the coroutine, and leaves it in a state where destruction is =
the only option, then why not just destroy the whole member activation reco=
rd and enter the terminal state during unwinding? Then the destructor never=
needs to know.</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-=
width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid=
; padding-left: 1ex; position: static; z-index: auto;"><div style=3D"word-w=
rap:break-word">2. Yield the <font face=3D"Courier">yield</font> =
keyword. The <font face=3D"Courier">return</font> keyword can imp=
lement <font face=3D"Courier">yield</font>, and only send the coroutin=
e to the terminal state when it’s the last statement in the function =
body.</div></blockquote><div><br></div><div>Are you a proponent of the sing=
le-entry-single-exit programming style? :) In normal functions we can have =
early return, so distinguishing return from yield mirrors this.</div></div>=
</blockquote><div><br></div><div>I’m actually a vehement opponent, bu=
t the point is mostly moot for coroutines.</div><div><br></div><div>1. Few =
coroutines have an early exit anyway. Most loop and exit at the end.</div><=
div>2. There’s no difference between yield and return, in the propose=
d system, except for when the user inspects the state. In many cases the st=
ate never gets inspected.</div><div>3. Another, more general, way to expres=
s early return would be <font face=3D"Courier">[]this.terminate()</font>.</=
div><div><br></div><div><font face=3D"Courier">// Status quo</font></div><d=
iv><font face=3D"Courier">if ( done ) return value;</font></div><div><font =
face=3D"Courier">else yield value;</font></div><div><font face=3D"Courier">=
<br></font></div><div><font face=3D"Courier">// Slightly simpler</font></di=
v><div><font face=3D"Courier">if ( done ) []this.terminate();</font></div><=
div><font face=3D"Courier">return value;</font></div><div><br></div><div>Th=
is style would require <font face=3D"Courier">return</font> to inspect the =
state before setting it, but that could be optimized out when it’s un=
conditional. Also, it would allow differentiating terminal and non-terminal=
exceptions.</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><blockquot=
e class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; border-left-wid=
th: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; p=
adding-left: 1ex; position: static; z-index: auto;"><div style=3D"word-wrap=
:break-word">3. Support exceptions. It’s nice to suspend a stack of c=
oroutines on an exception, and resume the entire stack. When an exception u=
nwinds a coroutine, it should update its state. This behavior would be unif=
orm with the above suggestion for <font face=3D"Courier">return</font>=
: any time a coroutine is exited, it is left ready to restart.<br></div></b=
lockquote><div><br></div><div>This sounds like an interesting idea, but I'd=
like to understand the context. Can you please explain the use cases for t=
his? Right now an exception will put the coroutine into the terminal state,=
to mirror what happens in a normal function.</div></div></blockquote><div>=
<br></div><div>The application is to allow an operation to be restarted aft=
er an exception. With serialization, you can resume processing after restar=
ting the process.</div><div><br></div><div>Actually, such “coroutines=
” don’t need <font face=3D"Courier">yield</font> at all, and it=
would be reasonable to want this without containment by a lambda. I don&rs=
quo;t think wrapping a restartable function in a lambda expression should c=
ause much trouble though.</div><br><blockquote type=3D"cite"><div dir=3D"lt=
r"><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0px 0.8ex; bo=
rder-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-st=
yle: solid; padding-left: 1ex; position: static; z-index: auto;"><div style=
=3D"word-wrap:break-word">The re-entry point saved by an exception is the (=
beginning of the) statement which threw it. Yes, writing such code is trick=
y, but it’s worth it.</div></blockquote><div><br></div><div>N.B. with=
the design as it is now, you can at least write "yield throw x;" to get th=
is behavior.</div></div></blockquote><div><br></div><div>Interesting. Is th=
is restricted to functions of void return type, i.e. a function can <font f=
ace=3D"Courier">yield value;</font> or <font face=3D"Courier">yield throw;<=
/font> but not both?</div><div><br></div><div>Why does the yield make a dif=
ference? I would think the throw would set the state to an unwind point, an=
d yield would not be reached at all.</div><br><blockquote type=3D"cite"><di=
v dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0px 0px 0p=
x 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); bor=
der-left-style: solid; padding-left: 1ex; position: static; z-index: auto;"=
><div style=3D"word-wrap:break-word">5. Serialization. This probably can on=
ly be a future direction, pending reflection capabilities, but a server wit=
h a million connections should have the ability to restart them after a fai=
lure. Resumable lambdas shouldn’t be bound to virtual memory.</div></=
blockquote><div><br></div><div>You are not the only one to suggest this... =
I have had someone ask about sending them over a network too. It seems feas=
ible to do this with reflection support.</div></div></blockquote><div><br><=
/div><div>I suppose the reflection can already be found if you store everyt=
hing in tuples.</div></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" 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=_580758BA-B414-46AC-BD20-1F453C5CB106--
.
Author: chris.kohlhoff@gmail.com
Date: Sat, 18 Oct 2014 16:36:54 -0700 (PDT)
Raw View
------=_Part_2002_1719955588.1413675414361
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Saturday, October 18, 2014 5:43:51 PM UTC+11, David Krauss wrote:
>
>
> On 2014=E2=80=9310=E2=80=9318, at 1:40 PM, chris.k...@gmail.com <javascri=
pt:> wrote:
>
> The state is updated for "yield" and "unwind" points, so I assume you are=
=20
> referring to the "unwind" points. Since the locals are implemented using=
=20
> data members we need to keep track of which ones have been constructed in=
=20
> order to run their destructors. Updating the state may not be the only wa=
y=20
> of accomplishing this, but that is why the demonstration code does this.
>
>
> Well, I was just looking at the example at the top of page 15, but really=
=20
> it=E2=80=99s not worth mentioning since the choice of update points can b=
e=20
> optimized by the implementation. Never mind.
>
> Not sure I understand how unwind points come into play. If an exception=
=20
> crosses the coroutine, and leaves it in a state where destruction is the=
=20
> only option, then why not just destroy the whole member activation record=
=20
> and enter the terminal state during unwinding? Then the destructor never=
=20
> needs to know.
>
I'm not sure I completely follow here, but it sounds like what you're=20
describing is what it does now. The unwind points update the __state member=
=20
as the list of live local variables has changed. When the exception is=20
thrown we run these variables' destructors in reverse order, just like what=
=20
happens in a normal function. The __state tells us which variables are live=
=20
and thus which ones need their destructors to be run.
=20
> 1. Few coroutines have an early exit anyway. Most loop and exit at the en=
d.
>
Hmm, I'm not sure I agree with that assessment. Probably true for things=20
like generators, less so when you're using coroutines to compose other=20
coroutines, as in asynchronous operations.
=20
> 2. There=E2=80=99s no difference between yield and return, in the propose=
d system,=20
> except for when the user inspects the state. In many cases the state neve=
r=20
> gets inspected.
>
When you use "yield from" on a sub-generator it always inspects the state.=
=20
=20
> 3. Another, more general, way to express early return would be=20
> []this.terminate().
>
=20
> // Status quo
> if ( done ) return value;
> else yield value;
>
> // Slightly simpler
> if ( done ) []this.terminate();
> return value;
>
Calling member functions on []this is neat idea. However, I'm not convinced=
=20
that only having a non-terminating return is a better choice, as it does=20
take the semantics of resumable lambdas further away from normal functions.=
=20
I think I don't fully appreciate the use case: why would you want to=20
restore only to the line immediately following an exception, as opposed to,=
=20
say, having explicit locations where you checkpoint the coroutine? E.g.:
yield checkpoint([]this); // saves a copy in case of exception
... do work ...
=20
> N.B. with the design as it is now, you can at least write "yield throw x;=
"=20
> to get this behavior.
>
>
> Interesting. Is this restricted to functions of void return type, i.e. a=
=20
> function can yield value; or yield throw; but not both?
>
It should work with any return type.=20
Why does the yield make a difference? I would think the throw would set the=
=20
> state to an unwind point, and yield would not be reached at all.
>
This is the behaviour of my current macro-based implementation. Using yield=
=20
expr; is roughly equivalent to:
state =3D __LINE__; expr; case __LINE__:
and when exiting a function (due to either return or throw), it first=20
checks if the state has already been set by a yield. If it has, then the=20
coroutine is not terminated.
Cheers,
Chris
--=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_2002_1719955588.1413675414361
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><br><br>On Saturday, October 18, 2014 5:43:51 PM UTC+11, D=
avid Krauss wrote:<blockquote class=3D"gmail_quote" style=3D"margin: 0;marg=
in-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=
=3D"word-wrap:break-word"><br><div><div>On 2014=E2=80=9310=E2=80=9318, at 1=
:40 PM, <a href=3D"javascript:" target=3D"_blank" gdf-obfuscated-mailto=3D"=
1o59QNvASwQJ" onmousedown=3D"this.href=3D'javascript:';return true;" onclic=
k=3D"this.href=3D'javascript:';return true;">chris.k...@gmail.com</a> wrote=
:</div><br><blockquote type=3D"cite"><div dir=3D"ltr"><div>The state is upd=
ated for "yield" and "unwind" points, so I assume you are referring to the =
"unwind" points. Since the locals are implemented using data members we nee=
d to keep track of which ones have been constructed in order to run their d=
estructors. Updating the state may not be the only way of accomplishing thi=
s, but that is why the demonstration code does this.</div></div></blockquot=
e><div><br></div><div>Well, I was just looking at the example at the top of=
page 15, but really it=E2=80=99s not worth mentioning since the choice of =
update points can be optimized by the implementation. Never mind.</div><div=
><br></div><div>Not sure I understand how unwind points come into play. If =
an exception crosses the coroutine, and leaves it in a state where destruct=
ion is the only option, then why not just destroy the whole member activati=
on record and enter the terminal state during unwinding? Then the destructo=
r never needs to know.</div></div></div></blockquote><div><br></div><div>I'=
m not sure I completely follow here, but it sounds like what you're describ=
ing is what it does now. The unwind points update the __state member as the=
list of live local variables has changed. When the exception is thrown we =
run these variables' destructors in reverse order, just like what happens i=
n a normal function. The __state tells us which variables are live and thus=
which ones need their destructors to be run.</div><div> </div><blockq=
uote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-lef=
t: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><=
div><div>1. Few coroutines have an early exit anyway. Most loop and exit at=
the end.</div></div></div></blockquote><div><br></div><div>Hmm, I'm not su=
re I agree with that assessment. Probably true for things like generators, =
less so when you're using coroutines to compose other coroutines, as in asy=
nchronous operations.</div><div> </div><blockquote class=3D"gmail_quot=
e" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;paddin=
g-left: 1ex;"><div style=3D"word-wrap:break-word"><div><div>2. There=E2=80=
=99s no difference between yield and return, in the proposed system, except=
for when the user inspects the state. In many cases the state never gets i=
nspected.</div></div></div></blockquote><div><br></div><div>When you use "y=
ield from" on a sub-generator it always inspects the state. </div><div=
> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-le=
ft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"wor=
d-wrap:break-word"><div><div>3. Another, more general, way to express early=
return would be <font face=3D"Courier">[]this.terminate()</font>.</div></d=
iv></div></blockquote><div> </div><blockquote class=3D"gmail_quote" st=
yle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-lef=
t: 1ex;"><div style=3D"word-wrap:break-word"><div><div><font face=3D"Courie=
r">// Status quo</font></div><div><font face=3D"Courier">if ( done ) return=
value;</font></div><div><font face=3D"Courier">else yield value;</font></d=
iv><div><font face=3D"Courier"><br></font></div><div><font face=3D"Courier"=
>// Slightly simpler</font></div><div><font face=3D"Courier">if ( done ) []=
this.terminate();</font></div><div><font face=3D"Courier">return value;</fo=
nt></div></div></div></blockquote><div><br></div><div>Calling member functi=
ons on []this is neat idea. However, I'm not convinced that only having a n=
on-terminating return is a better choice, as it does take the semantics of =
resumable lambdas further away from normal functions. I think I don't fully=
appreciate the use case: why would you want to restore only to the line im=
mediately following an exception, as opposed to, say, having explicit locat=
ions where you checkpoint the coroutine? E.g.:</div><div><br></div><div>&nb=
sp; yield checkpoint([]this); // saves a copy in case of exception</div><di=
v> ... do work ...</div><div> </div><blockquote class=3D"gmail_q=
uote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;pad=
ding-left: 1ex;"><div style=3D"word-wrap:break-word"><div><blockquote type=
=3D"cite"><div dir=3D"ltr"><div>N.B. with the design as it is now, you can =
at least write "yield throw x;" to get this behavior.</div></div></blockquo=
te><div><br></div><div>Interesting. Is this restricted to functions of void=
return type, i.e. a function can <font face=3D"Courier">yield value;</font=
> or <font face=3D"Courier">yield throw;</font> but not both?</div></div></=
div></blockquote><div><br></div><div>It should work with any return type.&n=
bsp;</div><div><br></div><blockquote class=3D"gmail_quote" style=3D"margin:=
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div =
style=3D"word-wrap:break-word"><div><div>Why does the yield make a differen=
ce? I would think the throw would set the state to an unwind point, and yie=
ld would not be reached at all.</div></div></div></blockquote><div><br></di=
v><div>This is the behaviour of my current macro-based implementation. Usin=
g yield expr; is roughly equivalent to:</div><div><br></div><div> sta=
te =3D __LINE__; expr; case __LINE__:</div><div><br></div><div>and when exi=
ting a function (due to either return or throw), it first checks if the sta=
te has already been set by a yield. If it has, then the coroutine is not te=
rminated.</div><div><br></div><div>Cheers,</div><div>Chris</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" 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_2002_1719955588.1413675414361--
.