Topic: Coroutines and continuations (N4244, N4134)
Author: Edward Catmur <ed@catmur.co.uk>
Date: Sun, 2 Nov 2014 15:37:43 -0800 (PST)
Raw View
------=_Part_1503_424710880.1414971463192
Content-Type: text/plain; charset=UTF-8
I've been following with interest the recent discussion on coroutines, and
wanted to present another option for extending the language. I believe that
the language construct that needs to be added is the (delimited)
continuation - the reification of a frame suspension point. Everything else
can be done at a library level.
My suggestion would be a statement syntax that constructs and adapts a
continuation closure, analogous to a lambda closure but executing the
remainder of the enclosing function from that suspension point:
[*capture-list*] [(*params*)]opt [-> *ret*]opt continue *expression*;
This is transformed into a return from the enclosing function, with the
return value being the result of calling the adaptor expression with the
continuation closure.
Example:
[=] continue std::generator::yield(n);
becomes
return std::generator::yield(n)(/* continuation-closure-type */{/*
closure-initializers */});
The differences between a continuation closure and a lambda closure are
minimal; the closure type is mutable by default, since the purpose of a
continuation is generally to mutate its automatic variables, and objects
captured by copy are initialized as by xvalues, since the initialization of
the continuation closure occurs within a return statement.
The continuation closure type has the usual member variables and a possibly
templated (if any of the continuation closure parameters are declared auto)
function call operator. The parameters of the function call operator are
the continuation closure parameters, if any. The body of the function call
operator consists of a copy of the enclosing function with the continuation
closure statement replaced with a label, and a jump to that label inserted
at the beginning of the operator body. Declarations of automatic variables
captured by the continuation closure are removed. If the jump bypasses
initialization of any remaining non-trivial automatic variables, the
program is ill-formed.
In this scheme, there are no resumable functions as such, just functions
containing continuation closure statements; such functions continue to be
callable with current ABI. Adapting a continuation (or multiple
continuations) to behave as a coroutine, generator, state machine etc. now
becomes a matter for the library. For example, coroutine await can be
written as:
template<class T>
auto await(std::future<T>&& future)
{
return [future = std::move(future)](auto&& continuation) mutable {
return std::async(std::launch::deferred,
[future = std::move(future), continuation = std::move(
continuation)]() mutable {
return continuation(future.get()).get(); }); };
}
Likewise, generator yield adapts continuations to a forward-iterable Range
concept, possibly moving continuations to heap storage and/or type-erasing
them; this is not necessary if a generator function has a single suspension
point.
A few things to consider:
- Distinct suspension points have distinct types, leading to possibly
faster code but also to code bloat; from my experience the implementation
can generally be relied upon to eliminate duplicate code.
- Because each suspension point has a distinct capture-list, the members
and thus size of the continuation closure types can vary between suspension
points of a function. I consider this a benefit; for example, a coroutine
implementing a network protocol can have different space demands through
its lifetime.
- No library support is required; continuation adaptors can be written
entirely independently of this language feature. No new keywords (unless
reuse of continue is considered too ugly).
- Accepting or yielding multiple values at a suspension point becomes
entirely straightforward (adaptor code may need to wrap values into tuples).
- This suggestion allows capturing by reference; a continuation that
captures automatic variables by reference can still be useful e.g. as a
variant visitor. An implementation could detect when a continuation
capturing automatic variables by reference is copied/moved outside its
enclosing frame.
- It might be beneficial to relax the rules for return type deduction
somewhat; for non-type-erased generators, the terminating return needs to
have the same type as the suspension point. It is possible to hack this
using decltype on the enclosing function, but it's pretty ugly (example
from n4244):
auto countdown(int n)
{
std::cout << "Counting down from " << n << std::endl;
while (n != 0)
{
[=] continue std::generator::yield(n);
--n;
}
return decltype(countdown(n))::halt();
}
- Non-movable non-copyable types, and objects prone to leaving dangling
references/pointers/iterators on moving (e.g. arrays) would need to be
heap-allocated prior to being captured, e.g. using make_unique. I find this
to be acceptable, especially as my suggestion would allow their owning
pointer to be automatically moved into the closure continuation capture.
For example, here's the coroutine from n4134:
std::future<std::ptrdiff_t> tcp_reader(int total)
{
constexpr std::size_t const bufSize = 64 * 1024;
auto buf = std::make_unique<char[]>(bufSize);
std::ptrdiff_t result = 0;
[=] (auto conn) continue await(tcp_connect("127.0.0.1", 1337));
do
{
auto ptr = buf.get();
[=] (auto bytesRead) continue await(tcp_read(conn, ptr, bufSize));
total -= bytesRead;
result += std::count(buf.get(), buf.get() + bytesRead), 'c');
}
while (total > 0);
std::promise<std::ptrdiff_t> promise;
promise.set_value(result);
return promise.get_future();
}
--
---
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_1503_424710880.1414971463192
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">I've been following with interest the recent discussion on=
coroutines, and wanted to present another option for extending the languag=
e. I believe that the language construct that needs to be added is the (del=
imited) continuation - the reification of a frame suspension point. Everyth=
ing else can be done at a library level.<div><br></div><div>My suggestion w=
ould be a statement syntax that constructs and adapts a continuation closur=
e, analogous to a lambda closure but executing the remainder of the enclosi=
ng function from that suspension point:</div><div><br></div><blockquote sty=
le=3D"margin: 0 0 0 40px; border: none; padding: 0px;"><font face=3D"courie=
r new, monospace">[<i>capture-list</i>] </font>[<font face=3D"courier new, =
monospace">(<i>params</i>)</font>]<font size=3D"1">opt</font><font face=3D"=
courier new, monospace"> </font>[<font face=3D"courier new, monospace">->=
; <i>ret</i></font>]<font size=3D"1">opt</font><font face=3D"courier new, m=
onospace"> continue <i>expression</i>;</font></blockquote><div><br></div><d=
iv>This is transformed into a return from the enclosing function, with the =
return value being the result of calling the adaptor <font face=3D"cou=
rier new, monospace">expression </font>with the continuation closure.<=
br><br></div><div>Example:</div><div><br></div><div><div class=3D"prettypri=
nt" style=3D"background-color: rgb(250, 250, 250); border: 1px solid rgb(18=
7, 187, 187); word-wrap: break-word;"><code class=3D"prettyprint"><div clas=
s=3D"subprettyprint"><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">[=3D]</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">continue</=
span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify">generator</span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">yield</span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">n</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">);</span></div></code></div><br></div><div>becomes</div><d=
iv><br></div><div class=3D"prettyprint" style=3D"background-color: rgb(250,=
250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: break-word;"><=
code class=3D"prettyprint"><div class=3D"subprettyprint"><span style=3D"col=
or: #008;" class=3D"styled-by-prettify">return</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify">generator</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #008;" class=3D"styl=
ed-by-prettify">yield</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">n</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)(</spa=
n><span style=3D"color: #800;" class=3D"styled-by-prettify">/* continuation=
-closure-type */</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">{</span><span style=3D"color: #800;" class=3D"styled-by-prettify">/* =
closure-initializers */</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">});</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br></span></div></code></div><div><br>The differences between a cont=
inuation closure and a lambda closure are minimal; the closure type is <fon=
t face=3D"courier new, monospace">mutable</font> by default, since the purp=
ose of a continuation is generally to mutate its automatic variables, and o=
bjects captured by copy are initialized as by xvalues, since the initializa=
tion of the continuation closure occurs within a return statement.</div><di=
v><br></div><div>The continuation closure type has the usual member variabl=
es and a possibly templated (if any of the continuation closure parameters =
are declared <font face=3D"courier new, monospace">auto</font>) function ca=
ll operator. The parameters of the function call operator are the continuat=
ion closure parameters, if any. The body of the function call operator cons=
ists of a copy of the enclosing function with the continuation closure stat=
ement replaced with a label, and a jump to that label inserted at the begin=
ning of the operator body. Declarations of automatic variables captured by =
the continuation closure are removed. If the jump bypasses initialization o=
f any remaining non-trivial automatic variables, the program is ill-formed.=
</div><div><br></div><div>In this scheme, there are no resumable functions =
as such, just functions containing continuation closure statements; such fu=
nctions continue to be callable with current ABI. Adapting a continuation (=
or multiple continuations) to behave as a coroutine, generator, state machi=
ne etc. now becomes a matter for the library. For example, coroutine await =
can be written as:</div><div><br></div><div class=3D"prettyprint" style=3D"=
background-color: rgb(250, 250, 250); border: 1px solid rgb(187, 187, 187);=
word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"subprett=
yprint"><span style=3D"color: #008;" class=3D"styled-by-prettify">template<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">class</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> T</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000;" =
class=3D"styled-by-prettify"> await</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">std</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>future</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><=
;</span><span style=3D"color: #000;" class=3D"styled-by-prettify">T</span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">>&&</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"> future</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">)</span><span sty=
le=3D"color: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">return</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">[</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify">future </span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> std</span><span style=3D"color: #660;" class=3D"styled-by-pretti=
fy">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">move=
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">future</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">)](</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">&&</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> continuation</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #008;" cla=
ss=3D"styled-by-prettify">mutable</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">{</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br> </span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify">async</span><span style=3D"color: #660;" class=3D"styled-by-prett=
ify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">std<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">launch</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify">deferred</span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">,</span><span style=3D"color: #00=
0;" class=3D"styled-by-prettify"><br> &nb=
sp; </span><span style=3D"color: #660;" class=3D"styled-by-prettify">[</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify">future </span><=
span style=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"> std</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify">move</span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify">future</span><span style=3D"color: #660;" class=3D"sty=
led-by-prettify">),</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> continuation </span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">move</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify">continuation</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">)]()</span><span styl=
e=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">mutable</span><span style=3D"color: =
#000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"><br> &nbs=
p; </span><span style=3D"color: #008;" class=3D"styled-by-prettify">return<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> continuati=
on</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">future</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">get</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">()).</span><span style=3D"color: #0=
08;" class=3D"styled-by-prettify">get</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">();</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">});</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #660;" class=3D"styled-by-prettify">};</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"><br></span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"><br></span></div></code></di=
v><div><br></div><div>Likewise, generator yield adapts continuations to a f=
orward-iterable Range concept, possibly moving continuations to heap storag=
e and/or type-erasing them; this is not necessary if a generator function h=
as a single suspension point.</div><div><br></div><div>A few things to cons=
ider:</div><div><ul><li>Distinct suspension points have distinct types, lea=
ding to possibly faster code but also to code bloat; from my experience the=
implementation can generally be relied upon to eliminate duplicate code.<b=
r></li><li>Because each suspension point has a distinct capture-list, the m=
embers and thus size of the continuation closure types can vary between sus=
pension points of a function. I consider this a benefit; for example, a cor=
outine implementing a network protocol can have different space demands thr=
ough its lifetime.</li><li>No library support is required; continuation ada=
ptors can be written entirely independently of this language feature. No ne=
w keywords (unless reuse of <font face=3D"courier new, monospace">continue<=
/font> is considered too ugly).</li><li>Accepting or yielding multiple valu=
es at a suspension point becomes entirely straightforward (adaptor code may=
need to wrap values into tuples).</li><li>This suggestion allows capturing=
by reference; a continuation that captures automatic variables by referenc=
e can still be useful e.g. as a variant visitor. An implementation could de=
tect when a continuation capturing automatic variables by reference is copi=
ed/moved outside its enclosing frame.</li><li>It might be beneficial to rel=
ax the rules for return type deduction somewhat; for non-type-erased genera=
tors, the terminating return needs to have the same type as the suspension =
point. It is possible to hack this using decltype on the enclosing function=
, but it's pretty ugly (example from n4244):<br></li></ul><div><span style=
=3D"line-height: 17px;"><div class=3D"prettyprint" style=3D"background-colo=
r: rgb(250, 250, 250); border: 1px solid rgb(187, 187, 187); word-wrap: bre=
ak-word;"><code class=3D"prettyprint"><div class=3D"subprettyprint"><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> count</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify">down</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #008;" c=
lass=3D"styled-by-prettify">int</span><span style=3D"color: #000;" class=3D=
"styled-by-prettify"> n</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> =
std</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">cout </s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify"><<</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #080;" class=3D"styled-by-prettify">"Counting down from "</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
style=3D"color: #660;" class=3D"styled-by-prettify"><<</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> n </span><span style=3D=
"color: #660;" class=3D"styled-by-prettify"><<</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: =
#660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">endl</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">;</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify"><br> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">while</span><span style=3D"color: #000;" class=3D"s=
tyled-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
>n </span><span style=3D"color: #660;" class=3D"styled-by-prettify">!=3D</s=
pan><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span=
style=3D"color: #066;" class=3D"styled-by-prettify">0</span><span style=3D=
"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"><br> </span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"><br> </span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">[=3D]</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"c=
olor: #008;" class=3D"styled-by-prettify">continue</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">generator</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">::</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">yield</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettif=
y">n</span><span style=3D"color: #660;" class=3D"styled-by-prettify">);</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify"><br> &nb=
sp; </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">--</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
n</span><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br> =
</span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify"><br> <=
/span><span style=3D"color: #008;" class=3D"styled-by-prettify">return</spa=
n><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span s=
tyle=3D"color: #008;" class=3D"styled-by-prettify">decltype</span><span sty=
le=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify">countdown</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify">n</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">))::</span><span style=3D"color: #000;" class=3D"style=
d-by-prettify">halt</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</s=
pan></div></code></div><div><ul style=3D"line-height: normal;"><li>Non-mova=
ble non-copyable types, and objects prone to leaving dangling references/po=
inters/iterators on moving (e.g. arrays) would need to be heap-allocated pr=
ior to being captured, e.g. using make_unique. I find this to be acceptable=
, especially as my suggestion would allow their owning pointer to be automa=
tically moved into the closure continuation capture. For example, here's th=
e coroutine from n4134:</li></ul></div><div><div class=3D"prettyprint" styl=
e=3D"background-color: rgb(250, 250, 250); border: 1px solid rgb(187, 187, =
187); word-wrap: break-word;"><code class=3D"prettyprint"><div class=3D"sub=
prettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">std<=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><s=
pan style=3D"color: #000;" class=3D"styled-by-prettify">future</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify">ptrdiff_t</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">></span><span style=3D"color: #000;" clas=
s=3D"styled-by-prettify"> tcp_reader</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">(</span><span style=3D"color: #008;" class=3D"sty=
led-by-prettify">int</span><span style=3D"color: #000;" class=3D"styled-by-=
prettify"> total</span><span style=3D"color: #660;" class=3D"styled-by-pret=
tify">)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br=
></span><span style=3D"color: #660;" class=3D"styled-by-prettify">{</span><=
span style=3D"color: #000;" class=3D"styled-by-prettify"><br> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">constexpr<=
/span><span style=3D"color: #000;" class=3D"styled-by-prettify"> std</span>=
<span style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">size_t </span><span style=
=3D"color: #008;" class=3D"styled-by-prettify">const</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"> bufSize </span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #0=
00;" class=3D"styled-by-prettify"> </span><span style=3D"color: #066;" clas=
s=3D"styled-by-prettify">64</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">*</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #066;" class=3D"styled-by-prettify">1024</span=
><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify"><br> </span>=
<span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"> buf </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"> std</span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">::</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">make_unique</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify"><</span><span style=3D"color: #008;" class=3D=
"styled-by-prettify">char</span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">[]>(</span><span style=3D"color: #000;" class=3D"styled-b=
y-prettify">bufSize</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
><br> std</span><span style=3D"color: #660;" class=3D"styled-b=
y-prettify">::</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy">ptrdiff_t result </span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">=3D</span><span style=3D"color: #000;" class=3D"styled-by-pretti=
fy"> </span><span style=3D"color: #066;" class=3D"styled-by-prettify">0</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span =
style=3D"color: #000;" class=3D"styled-by-prettify"><br> </spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">[=3D]</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color=
: #008;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #000=
;" class=3D"styled-by-prettify"> conn</span><span style=3D"color: #660;" cl=
ass=3D"styled-by-prettify">)</span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by-p=
rettify">continue</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> await</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify">tcp_co=
nnect</span><span style=3D"color: #660;" class=3D"styled-by-prettify">(</sp=
an><span style=3D"color: #080;" class=3D"styled-by-prettify">"127.0.0.1"</s=
pan><span style=3D"color: #660;" class=3D"styled-by-prettify">,</span><span=
style=3D"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D=
"color: #066;" class=3D"styled-by-prettify">1337</span><span style=3D"color=
: #660;" class=3D"styled-by-prettify">));</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br> </span><span style=3D"colo=
r: #008;" class=3D"styled-by-prettify">do</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify"><br> </span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">{</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br> </span><span =
style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> ptr </span><span style=3D"c=
olor: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"color: #=
000;" class=3D"styled-by-prettify"> buf</span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">.</span><span style=3D"color: #008;" class=3D"=
styled-by-prettify">get</span><span style=3D"color: #660;" class=3D"styled-=
by-prettify">();</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"><br> </span><span style=3D"color: #660;" c=
lass=3D"styled-by-prettify">[=3D]</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #660;" class=3D"style=
d-by-prettify">(</span><span style=3D"color: #008;" class=3D"styled-by-pret=
tify">auto</span><span style=3D"color: #000;" class=3D"styled-by-prettify">=
bytesRead</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
)</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #008;" class=3D"styled-by-prettify">continue</span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> await</span><span s=
tyle=3D"color: #660;" class=3D"styled-by-prettify">(</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify">tcp_read</span><span style=3D"col=
or: #660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;=
" class=3D"styled-by-prettify">conn</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"> ptr</span><span style=3D"color: #660;" class=3D"styled-by-=
prettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"=
> bufSize</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbs=
p; total </span><span style=3D"color: #660;" class=3D"=
styled-by-prettify">-=3D</span><span style=3D"color: #000;" class=3D"styled=
-by-prettify"> bytesRead</span><span style=3D"color: #660;" class=3D"styled=
-by-prettify">;</span><span style=3D"color: #000;" class=3D"styled-by-prett=
ify"><br> result </span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">+=3D</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify"> std</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify">count</span><span style=3D"color: #660;" class=3D"styled-by=
-prettify">(</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
">buf</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.</sp=
an><span style=3D"color: #008;" class=3D"styled-by-prettify">get</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">(),</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify"> buf</span><span style=3D"co=
lor: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">get</span><span style=3D"color: #660;" clas=
s=3D"styled-by-prettify">()</span><span style=3D"color: #000;" class=3D"sty=
led-by-prettify"> </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">+</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
bytesRead</span><span style=3D"color: #660;" class=3D"styled-by-prettify">)=
,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> </span><=
span style=3D"color: #080;" class=3D"styled-by-prettify">'c'</span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"c=
olor: #000;" class=3D"styled-by-prettify"><br> </span><span st=
yle=3D"color: #660;" class=3D"styled-by-prettify">}</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"><br> </span><span sty=
le=3D"color: #008;" class=3D"styled-by-prettify">while</span><span style=3D=
"color: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #=
660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify">total </span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">></span><span style=3D"color: #000;" class=3D"st=
yled-by-prettify"> </span><span style=3D"color: #066;" class=3D"styled-by-p=
rettify">0</span><span style=3D"color: #660;" class=3D"styled-by-prettify">=
);</span><span style=3D"color: #000;" class=3D"styled-by-prettify"><br>&nbs=
p; std</span><span style=3D"color: #660;" class=3D"styled-by-prettif=
y">::</span><span style=3D"color: #000;" class=3D"styled-by-prettify">promi=
se</span><span style=3D"color: #660;" class=3D"styled-by-prettify"><</sp=
an><span style=3D"color: #000;" class=3D"styled-by-prettify">std</span><spa=
n style=3D"color: #660;" class=3D"styled-by-prettify">::</span><span style=
=3D"color: #000;" class=3D"styled-by-prettify">ptrdiff_t</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">></span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> promise</span><span style=3D"colo=
r: #660;" class=3D"styled-by-prettify">;</span><span style=3D"color: #000;"=
class=3D"styled-by-prettify"><br> promise</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">.</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify">set_value</span><span style=3D"color:=
#660;" class=3D"styled-by-prettify">(</span><span style=3D"color: #000;" c=
lass=3D"styled-by-prettify">result</span><span style=3D"color: #660;" class=
=3D"styled-by-prettify">);</span><span style=3D"color: #000;" class=3D"styl=
ed-by-prettify"><br> </span><span style=3D"color: #008;" class=
=3D"styled-by-prettify">return</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> promise</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">.</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify">get_future</span><span style=3D"color: #660;" class=3D"styled-by-p=
rettify">();</span><span style=3D"color: #000;" class=3D"styled-by-prettify=
"><br></span><span style=3D"color: #660;" class=3D"styled-by-prettify">}</s=
pan></div></code></div><div><br></div></div></span></div></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_1503_424710880.1414971463192--
.
Author: David Krauss <potswa@gmail.com>
Date: Sun, 2 Nov 2014 23:38:39 -0600
Raw View
--Apple-Mail=_FA1118D7-AC3C-4940-A946-6A75E6590784
Content-Transfer-Encoding: quoted-printable
Content-Type: text/plain; charset=UTF-8
On 2014=E2=80=9311=E2=80=9302, at 5:37 PM, Edward Catmur <ed@catmur.co.uk> =
wrote:
> I've been following with interest the recent discussion on coroutines, an=
d wanted to present another option for extending the language. I believe th=
at the language construct that needs to be added is the (delimited) continu=
ation - the reification of a frame suspension point. Everything else can be=
done at a library level.
>=20
> My suggestion would be a statement syntax that constructs and adapts a co=
ntinuation closure, analogous to a lambda closure but executing the remaind=
er of the enclosing function from that suspension point:
I do like the idea of putting a function interface on a continuation, and r=
eusing the continue keyword, but=E2=80=A6
Where is the stack frame created when the function is first entered? If sus=
pension requires moving by-value captures into the closure object, that exc=
ludes capturing immovable locals. Also, capturing locals by reference would=
seem to be useless.
If suspension is conditional, the compiler would seem to need to generate s=
eparate code to access locals in the natural stack frame for a function tha=
t has not yet been suspended, and in a closure object if it has been resume=
d.
> [capture-list] [(params)]opt [-> ret]opt continue expression;
When can the user exclude a variable from the capture list? It seems to me =
that [=3D] is the only valid choice. Does using a variable in code reachabl=
e from the suspension point look it up both in the closure and the original=
function scope?
What do the parameters do? There=E2=80=99s no compound statement to use the=
m. The closure body is the enclosing function body, but name lookup from th=
ere will never find a closure parameter.
> Distinct suspension points have distinct types, leading to possibly faste=
r code but also to code bloat; from my experience the implementation can ge=
nerally be relied upon to eliminate duplicate code.
They produce different functions. Some compilers merge identical functions,=
but it=E2=80=99s not clear that=E2=80=99s what we have here.
> Because each suspension point has a distinct capture-list, the members an=
d thus size of the continuation closure types can vary between suspension p=
oints of a function. I consider this a benefit; for example, a coroutine im=
plementing a network protocol can have different space demands through its =
lifetime.
To realize this benefit, it would have to be reallocated completely on each=
suspension, which could be quite a bit of heap churn.
> No library support is required; continuation adaptors can be written enti=
rely independently of this language feature. No new keywords (unless reuse =
of continue is considered too ugly).
This is a tricky way to put it. Mere mortals cannot write the above await s=
o it would need to be part of the standard library. Also, while the other p=
roposals provide built-in closure type variance with a built-in union and s=
witch, in your proposal allowing one closure handle to represent several st=
ates requires the library to do dispatching and placement-new allocation. I=
t might be hard to write the dispatcher in an optimizer-friendly way.
> Accepting or yielding multiple values at a suspension point becomes entir=
ely straightforward (adaptor code may need to wrap values into tuples).
Return values need to be forwarded through a parameter to the adaptor. Eith=
er the adaptor is stored elsewhere, or the return value is stored in the ad=
aptor. The coroutine interface gets bound to its allocation scheme.
> This suggestion allows capturing by reference; a continuation that captur=
es automatic variables by reference can still be useful e.g. as a variant v=
isitor. An implementation could detect when a continuation capturing automa=
tic variables by reference is copied/moved outside its enclosing frame.
Can you give an example?
> It might be beneficial to relax the rules for return type deduction somew=
hat; for non-type-erased generators, the terminating return needs to have t=
he same type as the suspension point. It is possible to hack this using dec=
ltype on the enclosing function, but it's pretty ugly (example from n4244):
What relaxation would work? All return statements (reachable from the initi=
al entry point) need to provide compatible continuation handles. That cumbe=
rsome decltype is actually doing something useful.
> Non-movable non-copyable types, and objects prone to leaving dangling ref=
erences/pointers/iterators on moving (e.g. arrays) would need to be heap-al=
located prior to being captured, e.g. using make_unique.
Less reasonable for guard types.
--=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=_FA1118D7-AC3C-4940-A946-6A75E6590784
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset=UTF-8
<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=
=E2=80=9311=E2=80=9302, at 5:37 PM, Edward Catmur <<a href=3D"mailto:ed@=
catmur.co.uk">ed@catmur.co.uk</a>> wrote:</div><br class=3D"Apple-interc=
hange-newline"><blockquote type=3D"cite"><div dir=3D"ltr">I've been followi=
ng with interest the recent discussion on coroutines, and wanted to present=
another option for extending the language. I believe that the language con=
struct that needs to be added is the (delimited) continuation - the reifica=
tion of a frame suspension point. Everything else can be done at a library =
level.<div><br></div><div>My suggestion would be a statement syntax that co=
nstructs and adapts a continuation closure, analogous to a lambda closure b=
ut executing the remainder of the enclosing function from that suspension p=
oint:</div></div></blockquote><div><br></div><div>I do like the idea of put=
ting a function interface on a continuation, and reusing the <font face=3D"=
Courier">continue</font> keyword, but=E2=80=A6</div><div><br></div><div>Whe=
re is the stack frame created when the function is first entered? If suspen=
sion requires moving by-value captures into the closure object, that exclud=
es capturing immovable locals. Also, capturing locals by reference would se=
em to be useless.</div><div><br></div><div>If suspension is conditional, th=
e compiler would seem to need to generate separate code to access locals in=
the natural stack frame for a function that has not yet been suspended, an=
d in a closure object if it has been resumed.</div><br><blockquote type=3D"=
cite"><div dir=3D"ltr"><blockquote style=3D"margin: 0 0 0 40px; border: non=
e; padding: 0px;"><font face=3D"courier new, monospace">[<i>capture-list</i=
>] </font>[<font face=3D"courier new, monospace">(<i>params</i>)</font>]<fo=
nt size=3D"1">opt</font><font face=3D"courier new, monospace"> </font>[<fon=
t face=3D"courier new, monospace">-> <i>ret</i></font>]<font size=3D"1">=
opt</font><font face=3D"courier new, monospace"> continue <i>expression</i>=
;</font></blockquote></div></blockquote><div><br></div><div>When can the us=
er exclude a variable from the capture list? It seems to me that <font face=
=3D"Courier">[=3D]</font> is the only valid choice. Does using a variable i=
n code reachable from the suspension point look it up both in the closure a=
nd the original function scope?</div><div><br></div><div>What do the parame=
ters do? There=E2=80=99s no compound statement to use them. The closure bod=
y is the enclosing function body, but name lookup from there will never fin=
d a closure parameter.</div><div><br></div><blockquote type=3D"cite"><div d=
ir=3D"ltr"><div><ul><li>Distinct suspension points have distinct types, lea=
ding to possibly faster code but also to code bloat; from my experience the=
implementation can generally be relied upon to eliminate duplicate code.<b=
r></li></ul></div></div></blockquote>They produce different functions. Some=
compilers merge identical functions, but it=E2=80=99s not clear that=E2=80=
=99s what we have here.<br><blockquote type=3D"cite"><div dir=3D"ltr"><div>=
<ul><li>Because each suspension point has a distinct capture-list, the memb=
ers and thus size of the continuation closure types can vary between suspen=
sion points of a function. I consider this a benefit; for example, a corout=
ine implementing a network protocol can have different space demands throug=
h its lifetime.</li></ul></div></div></blockquote><div>To realize this bene=
fit, it would have to be reallocated completely on each suspension, which c=
ould be quite a bit of heap churn.</div><blockquote type=3D"cite"><div dir=
=3D"ltr"><div><ul><li>No library support is required; continuation adaptors=
can be written entirely independently of this language feature. No new key=
words (unless reuse of <font face=3D"courier new, monospace">continue</font=
> is considered too ugly).</li></ul></div></div></blockquote>This is a tric=
ky way to put it. Mere mortals cannot write the above <font face=3D"Courier=
">await</font> so it would need to be part of the standard library. Also, w=
hile the other proposals provide built-in closure type variance with a buil=
t-in <font face=3D"Courier">union</font> and <font face=3D"Courier">switch<=
/font>, in your proposal allowing one closure handle to represent several s=
tates requires the library to do dispatching and placement-new allocation. =
It might be hard to write the dispatcher in an optimizer-friendly way.<br><=
blockquote type=3D"cite"><div dir=3D"ltr"><div><ul><li>Accepting or yieldin=
g multiple values at a suspension point becomes entirely straightforward (a=
daptor code may need to wrap values into tuples).</li></ul></div></div></bl=
ockquote><div>Return values need to be forwarded through a parameter to the=
adaptor. Either the adaptor is stored elsewhere, or the return value is st=
ored in the adaptor. The coroutine interface gets bound to its allocation s=
cheme.</div><blockquote type=3D"cite"><div dir=3D"ltr"><div><ul><li>This su=
ggestion allows capturing by reference; a continuation that captures automa=
tic variables by reference can still be useful e.g. as a variant visitor. A=
n implementation could detect when a continuation capturing automatic varia=
bles by reference is copied/moved outside its enclosing frame.</li></ul></d=
iv></div></blockquote>Can you give an example?<br><blockquote type=3D"cite"=
><div dir=3D"ltr"><div><ul><li>It might be beneficial to relax the rules fo=
r return type deduction somewhat; for non-type-erased generators, the termi=
nating return needs to have the same type as the suspension point. It is po=
ssible to hack this using decltype on the enclosing function, but it's pret=
ty ugly (example from n4244):<br></li></ul></div></div></blockquote><div>Wh=
at relaxation would work? All return statements (reachable from the initial=
entry point) need to provide compatible continuation handles. That cumbers=
ome <font face=3D"Courier">decltype</font> is actually doing something usef=
ul.</div><blockquote type=3D"cite"><div dir=3D"ltr"><div><div><span style=
=3D"line-height: 17px;"><div><ul style=3D"line-height: normal;"><li>Non-mov=
able non-copyable types, and objects prone to leaving dangling references/p=
ointers/iterators on moving (e.g. arrays) would need to be heap-allocated p=
rior to being captured, e.g. using make_unique.</li></ul></div></span></div=
></div></div></blockquote><div>Less reasonable for guard types.</div><div><=
br></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=_FA1118D7-AC3C-4940-A946-6A75E6590784--
.
Author: edward.catmur@mavensecurities.com
Date: Mon, 3 Nov 2014 07:56:46 -0800 (PST)
Raw View
------=_Part_1285_210736908.1415030206337
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
On Monday, 3 November 2014 05:38:46 UTC, David Krauss wrote:
>
> Where is the stack frame created when the function is first entered? If=
=20
> suspension requires moving by-value captures into the closure object, tha=
t=20
> excludes capturing immovable locals. Also, capturing locals by reference=
=20
> would seem to be useless.
>
The initial stack frame would be a normal frame. It might make sense to=20
allow elision of capture, in which case the frame would be laid out as the=
=20
closure object, but move constructors would still need to be available.
=20
> If suspension is conditional, the compiler would seem to need to generate=
=20
> separate code to access locals in the natural stack frame for a function=
=20
> that has not yet been suspended, and in a closure object if it has been=
=20
> resumed.
>
> [*capture-list*] [(*params*)]opt [-> *ret*]opt continue *expression*;
>
>
> When can the user exclude a variable from the capture list? It seems to m=
e=20
> that [=3D] is the only valid choice.
>
A variable can be excluded if it is not required in the continuation;=20
sometimes it makes sense to be explicit.
=20
> Does using a variable in code reachable from the suspension point look it=
=20
> up both in the closure and the original function scope?
>
Lookup is in the closure if the continuation is being executed, in the=20
original function scope otherwise.
=20
> What do the parameters do? There=E2=80=99s no compound statement to use t=
hem. The=20
> closure body is the enclosing function body, but name lookup from there=
=20
> will never find a closure parameter.
>
Ah, sorry. Parameters (and init-captures) are available for name lookup in=
=20
the remainder of the immediately enclosing declarative region, as for an=20
automatic variable declared at that location. This probably means that=20
jumps into potential scope of a continuation capture (goto or switch) would=
=20
be illegal.
=20
>
> - Distinct suspension points have distinct types, leading to possibly=
=20
> faster code but also to code bloat; from my experience the implementat=
ion=20
> can generally be relied upon to eliminate duplicate code.
> =20
> They produce different functions. Some compilers merge identical=20
> functions, but it=E2=80=99s not clear that=E2=80=99s what we have here.=
=20
>
Correct; at the very least the entry points are different. This could be a=
=20
problem.
>
> - Because each suspension point has a distinct capture-list, the=20
> members and thus size of the continuation closure types can vary betwe=
en=20
> suspension points of a function. I consider this a benefit; for exampl=
e, a=20
> coroutine implementing a network protocol can have different space dem=
ands=20
> through its lifetime.
>
> To realize this benefit, it would have to be reallocated completely on=20
> each suspension, which could be quite a bit of heap churn.
>
Also a problem. Allocation reuse would be nice but might be a bit much to=
=20
ask for from the library.=20
>
> - No library support is required; continuation adaptors can be written=
=20
> entirely independently of this language feature. No new keywords (unle=
ss=20
> reuse of continue is considered too ugly).
>
> This is a tricky way to put it. Mere mortals cannot write the above await=
=20
> so it would need to be part of the standard library. Also, while the othe=
r=20
> proposals provide built-in closure type variance with a built-in union=20
> and switch, in your proposal allowing one closure handle to represent=20
> several states requires the library to do dispatching and placement-new=
=20
> allocation. It might be hard to write the dispatcher in an=20
> optimizer-friendly way.
>
Well, it seemed reasonably straightforward to me :). Adaptors can also be=
=20
made available in non-standard libraries (boost, etc.) allowing for=20
experimentation in implementation techniques. If a dispatcher doesn't need=
=20
to perform type erasure, then it can be written with switch just as a=20
built-in multiple-entry closure type would be.
>
> - Accepting or yielding multiple values at a suspension point becomes=
=20
> entirely straightforward (adaptor code may need to wrap values into tu=
ples).
>
> Return values need to be forwarded through a parameter to the adaptor.=20
> Either the adaptor is stored elsewhere, or the return value is stored in=
=20
> the adaptor. The coroutine interface gets bound to its allocation scheme.
>
Oh, definitely. Again, I see this as a benefit; it's putting full control=
=20
in the hands of the library implementor.=20
>
> - This suggestion allows capturing by reference; a continuation that=
=20
> captures automatic variables by reference can still be useful e.g. as =
a=20
> variant visitor. An implementation could detect when a continuation=20
> capturing automatic variables by reference is copied/moved outside its=
=20
> enclosing frame.
>
> Can you give an example?
>
Sure:
std::variant<std::string, int, double> v =3D some_function();
[&](auto&& v) continue [&](auto& cont) { return v.visit(cont); };
std::cout << v << std::endl;
Formally, two new stack frames are entered, with the lambda calling the=20
continuation; in practice, tail call elimination applies and the function=
=20
jumps to one of the three possible continuations.
>
> - It might be beneficial to relax the rules for return type deduction=
=20
> somewhat; for non-type-erased generators, the terminating return needs=
to=20
> have the same type as the suspension point. It is possible to hack thi=
s=20
> using decltype on the enclosing function, but it's pretty ugly (exampl=
e=20
> from n4244):
> =20
> What relaxation would work? All return statements (reachable from the=20
> initial entry point) need to provide compatible continuation handles. Tha=
t=20
> cumbersome decltype is actually doing something useful.
>
Allowing any type convertible to the first return type would be enough in=
=20
this case, i.e. return std:generator::halt with the generator type having a=
=20
std::generator::halt_t converting constructor. Ideally, some way of=20
providing custom unification of multiple return types; overriding=20
std::common_type<...>, though preferably with a non-library name.
>
> - Non-movable non-copyable types, and objects prone to leaving=20
> dangling references/pointers/iterators on moving (e.g. arrays) would n=
eed=20
> to be heap-allocated prior to being captured, e.g. using make_unique.
>
> Less reasonable for guard types.
>
Do we really want to encourage programmers to persist guard objects across=
=20
suspension points?
--=20
This e-mail together with any attachments (the "Message") is confidential=
=20
and may contain privileged information. If you are not the intended=20
recipient or if you have received this e-mail in error, please notify the=
=20
sender immediately and permanently delete this Message from your system. =
=20
Do not copy, disclose or distribute the information contained in this=20
Message.
=20
Maven Securities Holding Ltd (No. 07505438), Maven Trading Ltd (No.=20
07511928), Maven Derivatives Ltd (No. 07511840) & Maven Europe Ltd (No.=20
08966593) are registered as companies in England and their registered=20
office address is Camomile Court, 23 Camomile St London EC3A 7LL, United=20
Kingdom and their VAT No. is 135539016. Maven Derivatives Ltd only is=20
authorised and regulated by the Financial Conduct Authority (FRN 607267).
--=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_1285_210736908.1415030206337
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Monday, 3 November 2014 05:38:46 UTC, David Krauss wro=
te:<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><div>Where is the stack frame created when the function is fi=
rst entered? If suspension requires moving by-value captures into the closu=
re object, that excludes capturing immovable locals. Also, capturing locals=
by reference would seem to be useless.</div></div></div></blockquote><div>=
<br></div><div>The initial stack frame would be a normal frame. It might ma=
ke sense to allow elision of capture, in which case the frame would be laid=
out as the closure object, but move constructors would still need to be av=
ailable.</div><div> </div><blockquote class=3D"gmail_quote" style=3D"m=
argin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"=
><div style=3D"word-wrap:break-word"><div><div>If suspension is conditional=
, the compiler would seem to need to generate separate code to access local=
s in the natural stack frame for a function that has not yet been suspended=
, and in a closure object if it has been resumed.</div><br><blockquote type=
=3D"cite"><div dir=3D"ltr"><blockquote style=3D"margin:0 0 0 40px;border:no=
ne;padding:0px"><font face=3D"courier new, monospace">[<i>capture-list</i>]=
</font>[<font face=3D"courier new, monospace">(<i>params</i>)</font>]<font=
size=3D"1">opt</font><font face=3D"courier new, monospace"> </font>[<font =
face=3D"courier new, monospace">-> <i>ret</i></font>]<font size=3D"1">op=
t</font><font face=3D"courier new, monospace"> continue <i>expression</i>;<=
/font></blockquote></div></blockquote><div><br></div><div>When can the user=
exclude a variable from the capture list? It seems to me that <font face=
=3D"Courier">[=3D]</font> is the only valid choice.</div></div></div></bloc=
kquote><div><br></div><div>A variable can be excluded if it is not required=
in the continuation; sometimes it makes sense to be explicit.<br></div><di=
v> </div><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-l=
eft: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"wo=
rd-wrap:break-word"><div><div>Does using a variable in code reachable from =
the suspension point look it up both in the closure and the original functi=
on scope?</div></div></div></blockquote><div><br></div><div>Lookup is in th=
e closure if the continuation is being executed, in the original function s=
cope otherwise.</div><div> </div><blockquote class=3D"gmail_quote" sty=
le=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left=
: 1ex;"><div style=3D"word-wrap:break-word"><div><div>What do the parameter=
s do? There=E2=80=99s no compound statement to use them. The closure body i=
s the enclosing function body, but name lookup from there will never find a=
closure parameter.<br></div></div></div></blockquote><div><br></div><div>A=
h, sorry. Parameters (and init-captures) are available for name lookup in t=
he remainder of the immediately enclosing declarative region, as for an aut=
omatic variable declared at that location. This probably means that jumps i=
nto potential scope of a continuation capture (<font face=3D"courier new, m=
onospace">goto</font> or <font face=3D"courier new, monospace">switch</font=
>) would be illegal.</div><div> </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><blockquote type=3D"c=
ite"><div dir=3D"ltr"><div><ul><li>Distinct suspension points have distinct=
types, leading to possibly faster code but also to code bloat; from my exp=
erience the implementation can generally be relied upon to eliminate duplic=
ate code.<br></li></ul></div></div></blockquote>They produce different func=
tions. Some compilers merge identical functions, but it=E2=80=99s not clear=
that=E2=80=99s what we have here. </div></div></blockquote><div><br><=
/div><div>Correct; at the very least the entry points are different. This c=
ould be a problem.</div><blockquote class=3D"gmail_quote" style=3D"margin: =
0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div s=
tyle=3D"word-wrap:break-word"><div><blockquote type=3D"cite"><div dir=3D"lt=
r"><div><ul><li>Because each suspension point has a distinct capture-list, =
the members and thus size of the continuation closure types can vary betwee=
n suspension points of a function. I consider this a benefit; for example, =
a coroutine implementing a network protocol can have different space demand=
s through its lifetime.</li></ul></div></div></blockquote><div>To realize t=
his benefit, it would have to be reallocated completely on each suspension,=
which could be quite a bit of heap churn.</div></div></div></blockquote><d=
iv><br></div><div>Also a problem. Allocation reuse would be nice but might =
be a bit much to ask for from the library. </div><blockquote class=3D"=
gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc so=
lid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div><blockquot=
e type=3D"cite"><div dir=3D"ltr"><div><ul><li>No library support is require=
d; continuation adaptors can be written entirely independently of this lang=
uage feature. No new keywords (unless reuse of <font face=3D"courier new, m=
onospace">continue</font> is considered too ugly).</li></ul></div></div></b=
lockquote>This is a tricky way to put it. Mere mortals cannot write the abo=
ve <font face=3D"Courier">await</font> so it would need to be part of the s=
tandard library. Also, while the other proposals provide built-in closure t=
ype variance with a built-in <font face=3D"Courier">union</font> and <font =
face=3D"Courier">switch</font>, in your proposal allowing one closure handl=
e to represent several states requires the library to do dispatching and pl=
acement-new allocation. It might be hard to write the dispatcher in an opti=
mizer-friendly way.<br></div></div></blockquote><div><br></div><div>Well, i=
t seemed reasonably straightforward to me :). Adaptors can also be made ava=
ilable in non-standard libraries (boost, etc.) allowing for experimentation=
in implementation techniques. If a dispatcher doesn't need to perform type=
erasure, then it can be written with switch just as a built-in multiple-en=
try closure type would be.</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><blockquote type=3D"cite"><div d=
ir=3D"ltr"><div><ul><li>Accepting or yielding multiple values at a suspensi=
on point becomes entirely straightforward (adaptor code may need to wrap va=
lues into tuples).</li></ul></div></div></blockquote><div>Return values nee=
d to be forwarded through a parameter to the adaptor. Either the adaptor is=
stored elsewhere, or the return value is stored in the adaptor. The corout=
ine interface gets bound to its allocation scheme.</div></div></div></block=
quote><div><br></div><div>Oh, definitely. Again, I see this as a benefit; i=
t's putting full control in the hands of the library implementor. </di=
v><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;b=
order-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:brea=
k-word"><div><blockquote type=3D"cite"><div dir=3D"ltr"><div><ul><li>This s=
uggestion allows capturing by reference; a continuation that captures autom=
atic variables by reference can still be useful e.g. as a variant visitor. =
An implementation could detect when a continuation capturing automatic vari=
ables by reference is copied/moved outside its enclosing frame.</li></ul></=
div></div></blockquote>Can you give an example?<br></div></div></blockquote=
><div><br></div><div>Sure:</div><div><br></div><div class=3D"prettyprint" s=
tyle=3D"border: 1px solid rgb(187, 187, 187); word-wrap: break-word; backgr=
ound-color: rgb(250, 250, 250);"><code class=3D"prettyprint"><div class=3D"=
subprettyprint"><span style=3D"color: #000;" class=3D"styled-by-prettify">s=
td</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span=
><span style=3D"color: #000;" class=3D"styled-by-prettify">variant</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify"><</span><span st=
yle=3D"color: #000;" class=3D"styled-by-prettify">std</span><span style=3D"=
color: #660;" class=3D"styled-by-prettify">::</span><span style=3D"color: #=
008;" class=3D"styled-by-prettify">string</span><span style=3D"color: #660;=
" class=3D"styled-by-prettify">,</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"style=
d-by-prettify">int</span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify">,</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> =
</span><span style=3D"color: #008;" class=3D"styled-by-prettify">double</sp=
an><span style=3D"color: #660;" class=3D"styled-by-prettify">></span><sp=
an style=3D"color: #000;" class=3D"styled-by-prettify"> v </span><span styl=
e=3D"color: #660;" class=3D"styled-by-prettify">=3D</span><span style=3D"co=
lor: #000;" class=3D"styled-by-prettify"> some_function</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">();</span><span style=3D"col=
or: #000;" class=3D"styled-by-prettify"><br></span><span style=3D"color: #6=
60;" class=3D"styled-by-prettify">[&](</span><span style=3D"color: #008=
;" class=3D"styled-by-prettify">auto</span><span style=3D"color: #660;" cla=
ss=3D"styled-by-prettify">&&</span><span style=3D"color: #000;" cla=
ss=3D"styled-by-prettify"> v</span><span style=3D"color: #660;" class=3D"st=
yled-by-prettify">)</span><span style=3D"color: #000;" class=3D"styled-by-p=
rettify"> </span><span style=3D"color: #008;" class=3D"styled-by-prettify">=
continue</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> <=
/span><span style=3D"color: #660;" class=3D"styled-by-prettify">[&](</s=
pan><span style=3D"color: #008;" class=3D"styled-by-prettify">auto</span><s=
pan style=3D"color: #660;" class=3D"styled-by-prettify">&</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify"> cont</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">)</span><span style=3D"color=
: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;" =
class=3D"styled-by-prettify">{</span><span style=3D"color: #000;" class=3D"=
styled-by-prettify"> </span><span style=3D"color: #008;" class=3D"styled-by=
-prettify">return</span><span style=3D"color: #000;" class=3D"styled-by-pre=
ttify"> v</span><span style=3D"color: #660;" class=3D"styled-by-prettify">.=
</span><span style=3D"color: #000;" class=3D"styled-by-prettify">visit</spa=
n><span style=3D"color: #660;" class=3D"styled-by-prettify">(</span><span s=
tyle=3D"color: #000;" class=3D"styled-by-prettify">cont</span><span style=
=3D"color: #660;" class=3D"styled-by-prettify">);</span><span style=3D"colo=
r: #000;" class=3D"styled-by-prettify"> </span><span style=3D"color: #660;"=
class=3D"styled-by-prettify">};</span><span style=3D"color: #000;" class=
=3D"styled-by-prettify"><br>std</span><span style=3D"color: #660;" class=3D=
"styled-by-prettify">::</span><span style=3D"color: #000;" class=3D"styled-=
by-prettify">cout </span><span style=3D"color: #660;" class=3D"styled-by-pr=
ettify"><<</span><span style=3D"color: #000;" class=3D"styled-by-pret=
tify"> v </span><span style=3D"color: #660;" class=3D"styled-by-prettify">&=
lt;<</span><span style=3D"color: #000;" class=3D"styled-by-prettify"> st=
d</span><span style=3D"color: #660;" class=3D"styled-by-prettify">::</span>=
<span style=3D"color: #000;" class=3D"styled-by-prettify">endl</span><span =
style=3D"color: #660;" class=3D"styled-by-prettify">;</span><span style=3D"=
color: #000;" class=3D"styled-by-prettify"><br></span></div></code></div><d=
iv><br></div><div>Formally, two new stack frames are entered, with the lamb=
da calling the continuation; in practice, tail call elimination applies and=
the function jumps to one of the three possible continuations.<br></div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-wo=
rd"><div><blockquote type=3D"cite"><div dir=3D"ltr"><div><ul><li>It might b=
e beneficial to relax the rules for return type deduction somewhat; for non=
-type-erased generators, the terminating return needs to have the same type=
as the suspension point. It is possible to hack this using decltype on the=
enclosing function, but it's pretty ugly (example from n4244):<br></li></u=
l></div></div></blockquote><div>What relaxation would work? All return stat=
ements (reachable from the initial entry point) need to provide compatible =
continuation handles. That cumbersome <font face=3D"Courier">decltype</font=
> is actually doing something useful.</div></div></div></blockquote><div><b=
r></div><div>Allowing any type convertible to the first return type would b=
e enough in this case, i.e. <font face=3D"courier new, monospace">return st=
d:generator::halt</font> with the generator type having a <font face=3D"cou=
rier new, monospace">std::generator::halt_t</font> converting constructor. =
Ideally, some way of providing custom unification of multiple return types;=
overriding <font face=3D"courier new, monospace">std::common_type<=
....></font>, though preferably with a non-library name.</div><blockquote=
class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1=
px #ccc solid;padding-left: 1ex;"><div style=3D"word-wrap:break-word"><div>=
<blockquote type=3D"cite"><div dir=3D"ltr"><div><div><span style=3D"line-he=
ight:17px"><div><ul style=3D"line-height:normal"><li>Non-movable non-copyab=
le types, and objects prone to leaving dangling references/pointers/iterato=
rs on moving (e.g. arrays) would need to be heap-allocated prior to being c=
aptured, e.g. using make_unique.</li></ul></div></span></div></div></div></=
blockquote><div>Less reasonable for guard types.</div></div></div></blockqu=
ote><div><br></div><div>Do we really want to encourage programmers to persi=
st guard objects across suspension points?</div></div>
<br>
<p><span lang=3D"EN" style=3D"font-size:7.5pt;font-family:"Arial"=
,"sans-serif";color:#222222;background:white">This e-mail togethe=
r with
any attachments (the "Message") is confidential and may contain
privileged information. If you are not the intended recipient or if you hav=
e
received this e-mail in error, please notify the sender immediately and
permanently delete this Message from your system.=C2=A0 Do not copy, disclo=
se
or distribute the information contained in this Message.</span></p>
<p><span lang=3D"EN" style=3D"font-size:7.5pt;font-family:"Arial"=
,"sans-serif";color:#222222;background:white">=C2=A0</span></p>
<p><span lang=3D"EN" style=3D"font-size:7.5pt;font-family:"Arial"=
,"sans-serif";color:#222222;background:white">Maven Securities Ho=
lding
Ltd (No. 07505438), Maven Trading Ltd (No. 07511928), Maven Derivatives Ltd
(No. 07511840) & Maven Europe Ltd (No. 08966593) are registered as
companies in England and their registered office address is Camomile Court,=
23
Camomile St London EC3A 7LL, United Kingdom and their VAT No. is 135539016.
Maven Derivatives Ltd only is authorised and regulated by the Financial Con=
duct
Authority (FRN 607267).</span></p>
<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_1285_210736908.1415030206337--
.