Topic: Questions / comments about p0057r2 coroutines
Author: alexander.vandergrinten@gmail.com
Date: Fri, 15 Jul 2016 02:33:16 -0700 (PDT)
Raw View
------=_Part_1589_409325685.1468575196876
Content-Type: multipart/alternative;
boundary="----=_Part_1590_809800214.1468575196876"
------=_Part_1590_809800214.1468575196876
Content-Type: text/plain; charset=UTF-8
Hi,
I have a few questions regarding the coroutine proposal p0057r2. I tried to
find the rationale behind those things in the paper's predecessors but that
is quite a bit of material to read so it's not impossible I missed the
reasoning there.
- AFAICS the proposal does not define a life time for the result of
coroutine_handle<P>::address(). I agree that address() and from_address()
are necessary for interfacing with C functions but it should be
well-defined until which point reconstructing a coroutine_handle<P> is
still valid.
- The from_promise() machinery seems very easy to misuse (as constructing a
coroutine promise yourself and passing it to from_promise() is undefined
behaviour) but I understand that it is necessary to implement generators.
Would passing a coroutine_handle<P> to get_return_object() not be a much
cleaner alternative / was such an approach considered yet?
- There are valid reasons for co_yield (mainly that other programming
languages have it) and it unlikely to be changed at this stage but an
alternative to co_yield would be a co_this expression that evaluates to a
reference (or pointer, for consistency with regular this) to the promise
object of the containing coroutine. That way co_yield could be written as
co_await co_this->yield() which is only marginally more code and uses a
more minimal primitive.
Aside from those minor points I think that p0057r2 is a major step forward
towards scaleable stackless coroutines and quite a well-designed proposal
that avoids most pitfalls of earlier papers.
Thanks,
Alexander van der Grinten
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/5c977d1e-6297-43bf-80cd-6997e403e543%40isocpp.org.
------=_Part_1590_809800214.1468575196876
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi,<br></div><div><br></div><div>I have a few questio=
ns regarding the coroutine proposal p0057r2. I tried to find the rationale =
behind those things in the paper's predecessors but that is quite a bit=
of material to read so it's not impossible I missed the reasoning ther=
e.</div><div><br></div><div>- AFAICS the proposal does not define a life ti=
me for the result of coroutine_handle<P>::address(). I agree that add=
ress() and from_address() are necessary for interfacing with C functions bu=
t it should be well-defined until which point reconstructing a coroutine_ha=
ndle<P> is still valid.</div><div><br></div><div>- The from_promise()=
machinery seems very easy to misuse (as constructing a coroutine promise y=
ourself and passing it to from_promise() is undefined behaviour) but I unde=
rstand that it is necessary to implement generators. Would passing a corout=
ine_handle<P> to get_return_object() not be a much cleaner alternativ=
e / was such an approach considered yet?</div><div><br></div><div>- There a=
re valid reasons for co_yield (mainly that other programming languages have=
it) and it unlikely to be changed at this stage but an alternative to co_y=
ield would be a co_this expression that evaluates to a reference (or pointe=
r, for consistency with regular this) to the promise object of the containi=
ng coroutine. That way co_yield could be written as co_await co_this->yi=
eld() which is only marginally more code and uses a more minimal primitive.=
</div><div><br></div><div>Aside from those minor points I think that p0057r=
2 is a major step forward towards scaleable stackless coroutines and quite =
a well-designed proposal that avoids most pitfalls of earlier papers.</div>=
<div><br></div><div>Thanks,</div><div>Alexander van der Grinten</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/5c977d1e-6297-43bf-80cd-6997e403e543%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/5c977d1e-6297-43bf-80cd-6997e403e543=
%40isocpp.org</a>.<br />
------=_Part_1590_809800214.1468575196876--
------=_Part_1589_409325685.1468575196876--
.
Author: Gor Nishanov <gornishanov@gmail.com>
Date: Sat, 16 Jul 2016 21:26:28 -0700 (PDT)
Raw View
------=_Part_149_1026018235.1468729588836
Content-Type: multipart/alternative;
boundary="----=_Part_150_1055901179.1468729588837"
------=_Part_150_1055901179.1468729588837
Content-Type: text/plain; charset=UTF-8
Hi Alexander:
>> functions but it should be well-defined until which point reconstructing
a coroutine_handle<P> is still valid.
Library Group has not looked at that part of the wording. They may very
well add the wording to that extent. Currently in P0057 whether coroutine
handle is usable or not is derived from magical "Requires: *this refers to
a suspended coroutine.", does not matter how you obtained the
coroutine_handle, as long as it refers to a suspended coroutine you can
call resume, done or destroy on it.
>> Would passing a coroutine_handle<P> to get_return_object() not be a much
cleaner alternative / was such an approach considered yet?
Yes. This was considered. It was a close call which way to go. Given that
having from_promise is allowing for symmetry with untyped promise,
potentially less parameters to pass to get_return_object, and that all of
these machinery are sharp objects for library writers and not for use by
most of the C++ users, there was a slight preference for the current
version. Either approach is fine. (With one caveat: current approach was in
the hand of customers for several years, another one was never tried, so
"fine" is purely a conjecture).
>> expression that evaluates to a reference (or pointer, for consistency
with regular this) to the promise object of the containing coroutine. That
way co_yield could be written as co_await co_this->yield() which is only
marginally more code and uses a more minimal primitive.
We added await_transform in P0057R1, it can be used to do what you are
suggesting. You can remove co_yield completely and implement it via
await_transform with some yield_t tag type.
Something like:
co_await yield_t(5)
You would specialize await_transform for yield_t to do what currently
yield_value does.
You can also have an await_transform for all other types that are not
yield_t to result in static_assert, so as to ban any other use of await,
apart from with yield_t type.
Cheers,
Gor
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/ceb459a7-65b0-47d5-9b05-ace701957d39%40isocpp.org.
------=_Part_150_1055901179.1468729588837
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi Alexander:</div><div><br></div><div>>> funct=
ions but it should be well-defined until which point reconstructing a corou=
tine_handle<P> is still valid.</div><div><br></div><div>Library Group=
has not looked at that part of the wording. They may very well add the wor=
ding to that extent. Currently in P0057 whether coroutine handle is usable =
or not is derived from magical "Requires: *this refers to a suspended =
coroutine.", does not matter how you obtained the coroutine_handle, as=
long as it refers to a suspended coroutine you can call resume, done=C2=A0=
or destroy on it.</div><div><br></div><div>>> Would passing a corouti=
ne_handle<P> to get_return_object() not be a much cleaner alternative=
/ was such an approach considered yet?</div><div><br></div><div>Yes. This =
was considered. It was a close call which way to go. Given that having from=
_promise is allowing for symmetry with untyped promise, potentially less pa=
rameters to pass to get_return_object, and that all of these machinery are =
sharp objects for library writers and not for use by most of the C++ users,=
there was a slight preference for the current version. Either approach is =
fine. (With one caveat: current approach was in the hand of customers for s=
everal years, another one was never tried, so "fine" is purely=C2=
=A0a conjecture).</div><div><br></div><div>>> expression that evaluat=
es to a reference (or pointer, for consistency with regular this) to the pr=
omise object of the containing coroutine. That way co_yield could be writte=
n as co_await co_this->yield() which is only marginally more code and us=
es a more minimal primitive.</div><div><br></div><div>We added await_transf=
orm in P0057R1, it can be used to do what you are suggesting. You can remov=
e co_yield completely and implement it=C2=A0via await_transform with some y=
ield_t tag type. </div><div><br></div><div>Something like:</div><div><br></=
div><div>co_await yield_t(5)</div><div><br></div><div>You would specialize =
await_transform for yield_t to do what currently yield_value does.</div><di=
v>You can also have an await_transform for all other types that are not yie=
ld_t to result in static_assert, so as to ban any other use of await, apart=
from with yield_t type.</div><div><br></div><div>Cheers,</div><div>Gor</di=
v></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/ceb459a7-65b0-47d5-9b05-ace701957d39%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/ceb459a7-65b0-47d5-9b05-ace701957d39=
%40isocpp.org</a>.<br />
------=_Part_150_1055901179.1468729588837--
------=_Part_149_1026018235.1468729588836--
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Mon, 18 Jul 2016 04:14:34 -0700 (PDT)
Raw View
------=_Part_4019_1685829110.1468840474934
Content-Type: multipart/alternative;
boundary="----=_Part_4020_749770267.1468840474934"
------=_Part_4020_749770267.1468840474934
Content-Type: text/plain; charset=UTF-8
Hello Gor,
thank you for taking the time to answer my comments.
>> Given that having from_promise is allowing for symmetry with untyped
promise, [...]
Well, address() and from_address() is not strictly necessary either, right?
It can always be replaced by the following pattern:
void do_something_async(void (*callback) (void *), void *argument);
/* ... */
auto operator await(/* ... */) {
struct awaitable {
void await_suspend(coroutine_handle<> handle) {
_handle = handle;
do_something_async([] (void *argument) {
auto self = static_cast<awaitable *>(argument);
self->_handle.resume();
}, this);
// The awaitable object is alive until the
// await-expression completes, so this is fine.
}
/* ... */
coroutine_handle<> _handle;
}
return awaitable(/* ... */);
}
This pattern is more general than address() / from_address(): It allows to
store additional parameters the callback receives in the awaitable object
can return them from await_resume. This enables users to implement non-void
await regardless of the underlying promise type; something which is not
possible with address() / from_address()! Why does the proposal include an
explicit address() / from_address() instead of promoting the use of this
store-handle-in-awaitable pattern?
>> We added await_transform in P0057R1, it can be used to do what you are
suggesting.
I see, this is indeed a much better idea than what I was suggesting.
Let me ask you another question: Why does the proposal _only_ provide
type-erased coroutine_handles? A call to resume() / done() / destroy()
results in an indirect jump. I agree that the compiler should be able to
devirtualize this jump in many cases; I also agree that having the
coroutine_handle of the prosal is important. But why don't we do something
like the following:
Define a `suspend-point handle` as a type that has the same interface as
coroutine_handle but has weaker guarantees: resume() / done() and destroy()
must only be called while the underlying coroutine is suspended in exactly
the same execution of the await-expression it was constructed for. Add an
implicit conversion from each `suspend-point handle` type to
coroutine_handle. Pass a `suspend-point handle` instead of a
coroutine_handle to await_suspend().
This way we can write await_suspend like this:
template<typename H>
void await_suspend(H handle);
// This is specialized for each await-expression, so that the compiler
can
// avoid using indirect calls for resume() / done() / destory() here.
void await_suspend(coroutine_handle<> handle);
// Still works the same as before. Uses the implicit conversion to
construct
// a coroutine_handle<>.
I feel like doing this has zero downsides. Sure, it is a code size for
speed trade-off but it is opt-in so that await operators for commonly used
types like std::future would still be able to use the more conservative
coroutine_handle. It has a niche for code where the failure to devirtualize
an indirect jump would result in a noticeable performance overhead:
Consider using await to read from a fast in-memory cache. The fast-path of
such a operation might be a single atomic load-acquire (aka a usual
non-atomic load on x86_64) and a indirect call would dominate the run time
of the whole operation. Also note that devirtualization is a relatively
complex optimization and might not be possible in some cases (e.g. when
code in a different translation unit is invoked and the compiler is unable
to prove that this code does not change the target of the jump (e.g. by
resuming the coroutine and suspending again); or just when compiling in
debug mode). Using this technique resume() would be so fast (it would
always be inlined and often be completely removed by an optimizing
compiler) that one could decide to abolish await_ready.
Note than in order to enable the store-handle-in-awaitable pattern from
above together with this technique the handle would need to be passed to
operator await (and not to await_suspend). This would allow us to convert
existing C-style callbacks to await in a very natural way and without using
any indirect jumps or address() magic:
template<typename H>
auto operator await(std::chrono::seconds t, H handle) {
struct awaitable {
awaitable(std::chrono::seconds t, H handle)
: _t(t), _handle(handle) { }
void await_suspend() {
call_in_n_seconds(_t.count(), [] (void *argument) {
auto self = static_cast<awaitable *>(argument);
self->_handle.resume();
}, this);
}
std::chrono::seconds _t;
H _handle;
};
return awaitable(t, handle);
}
Many thanks,
Alexander
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c2ccd580-126c-42f0-967c-bdb9fc72f890%40isocpp.org.
------=_Part_4020_749770267.1468840474934
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hello Gor,<br></div><div><br></div><div>thank you for=
taking the time to answer my comments.</div><div><br></div><div>>> G=
iven that having from_promise is allowing for symmetry with untyped promise=
, [...]</div><div><br></div><div>Well, address() and from_address() is not =
strictly necessary either, right? It can always be replaced by the followin=
g pattern:</div><div><br></div><div>=C2=A0 =C2=A0 void do_something_async(v=
oid (*callback) (void *), void *argument);</div><div><br></div><div>=C2=A0 =
=C2=A0 /* ... */</div><div><br></div><div>=C2=A0 =C2=A0 auto operator await=
(/* ... */) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct awaitable {</div=
><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await_suspend(coroutin=
e_handle<> handle) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 _handle =3D handle;</div><div><br></div><div>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 do_something_async([] (void *=
argument) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 auto self =3D static_cast<awaitable *>(argument);</=
div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 self->_handle.resume();</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 }, this);</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 // The awaitable object is alive until the</div><d=
iv>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // await-express=
ion completes, so this is fine.</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 }</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 /* ... */</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 coroutine_handle<> _handle;</div><div>=C2=A0 =C2=A0 =C2=A0=
=C2=A0 }</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return await=
able(/* ... */);</div><div>=C2=A0 =C2=A0 }</div><div><br></div><div>This pa=
ttern is more general than address() / from_address(): It allows to store a=
dditional parameters the callback receives in the awaitable object can retu=
rn them from await_resume. This enables users to implement non-void await r=
egardless of the underlying promise type; something which is not possible w=
ith address() / from_address()! Why does the proposal include an explicit a=
ddress() / from_address() instead of promoting the use of this store-handle=
-in-awaitable pattern?</div><div><br></div><div>>> We added await_tra=
nsform in P0057R1, it can be used to do what you are suggesting.</div><div>=
<br></div><div>I see, this is indeed a much better idea than what I was sug=
gesting.</div><div><br></div><div><br></div><div>Let me ask you another que=
stion: Why does the proposal _only_ provide type-erased coroutine_handles? =
A call to resume() / done() / destroy() results in an indirect jump. I agre=
e that the compiler should be able to devirtualize this jump in many cases;=
I also agree that having the coroutine_handle of the prosal is important. =
But why don't we do something like the following:</div><div><br></div><=
div>Define a `suspend-point handle` as a type that has the same interface a=
s coroutine_handle but has weaker guarantees: resume() / done() and destroy=
() must only be called while the underlying coroutine is suspended in exact=
ly the same execution of the await-expression it was constructed for. Add a=
n implicit conversion from each `suspend-point handle` type to coroutine_ha=
ndle. Pass a `suspend-point handle` instead of a coroutine_handle to await_=
suspend().</div><div><br></div><div>This way we can write await_suspend lik=
e this:</div><div><br></div><div>=C2=A0 =C2=A0 template<typename H></=
div><div>=C2=A0 =C2=A0 void await_suspend(H handle);</div><div>=C2=A0 =C2=
=A0 // This is specialized for each await-expression, so that the compiler =
can</div><div>=C2=A0 =C2=A0 // avoid using indirect calls for resume() / do=
ne() / destory() here.</div><div><br></div><div>=C2=A0 =C2=A0 void await_su=
spend(coroutine_handle<> handle);</div><div>=C2=A0 =C2=A0 // Still wo=
rks the same as before. Uses the implicit conversion to construct</div><div=
>=C2=A0 =C2=A0 // a coroutine_handle<>.</div><div><br></div><div>I fe=
el like doing this has zero downsides. Sure, it is a code size for speed tr=
ade-off but it is opt-in so that await operators for commonly used types li=
ke std::future would still be able to use the more conservative coroutine_h=
andle. It has a niche for code where the failure to devirtualize an indirec=
t jump would result in a noticeable performance overhead: Consider using aw=
ait to read from a fast in-memory cache. The fast-path of such a operation =
might be a single atomic load-acquire (aka a usual non-atomic load on x86_6=
4) and a indirect call would dominate the run time of the whole operation. =
Also note that devirtualization is a relatively complex optimization and mi=
ght not be possible in some cases (e.g. when code in a different translatio=
n unit is invoked and the compiler is unable to prove that this code does n=
ot change the target of the jump (e.g. by resuming the coroutine and suspen=
ding again); or just when compiling in debug mode). Using this technique re=
sume() would be so fast (it would always be inlined and often be completely=
removed by an optimizing compiler) that one could decide to abolish await_=
ready.</div><div><br></div><div>Note than in order to enable the store-hand=
le-in-awaitable pattern from above together with this technique the handle =
would need to be passed to operator await (and not to await_suspend). This =
would allow us to convert existing C-style callbacks to await in a very nat=
ural way and without using any indirect jumps or address() magic:</div><div=
><br></div><div>=C2=A0 =C2=A0 template<typename H></div><div>=C2=A0 =
=C2=A0 auto operator await(std::chrono::seconds t, H handle) {</div><div>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct awaitable {</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 awaitable(std::chrono::seconds t, H handle)</div><=
div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 : _t(t), _handle(handle) { }<=
/div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void awa=
it_suspend() {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 call_in_n_seconds(_t.count(), [] (void *argument) {</div><div>=C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 auto self =
=3D static_cast<awaitable *>(argument);</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 self->_handle.resum=
e();</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }, t=
his);</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }</div><div><br><=
/div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 std::chrono::seconds _t=
;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 H _handle;</div><div>=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</div><div><br></div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 return awaitable(t, handle);</div><div>=C2=A0 =C2=A0 }</div><div=
><br></div><div>Many thanks,</div><div>Alexander</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c2ccd580-126c-42f0-967c-bdb9fc72f890%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c2ccd580-126c-42f0-967c-bdb9fc72f890=
%40isocpp.org</a>.<br />
------=_Part_4020_749770267.1468840474934--
------=_Part_4019_1685829110.1468840474934--
.
Author: Gor Nishanov <gornishanov@gmail.com>
Date: Tue, 19 Jul 2016 10:13:56 -0700
Raw View
Hi Alexander:
You can go even bolder and design a coroutine model that does not need
coroutine_handle at all.
Imagine that at every suspend point, you are given an object:
h
for which you can call:
h.on_value(T) or h(T)
h.on_error(E)
where T is the result type for that await (may be different for every
await) and E is the error (probably the same E for entire coroutine).
Then you are free to do whatever you want is it.
(Combined with get_return_object getting the same object that you can
store in the promise yourself).
Say, you opt-into this model on top of p0057 by adding
get_coroutine_handle to your promise.
That is a nice model. It needs to be designed and prototyped, but,
otherwise, I can see how C++ coroutines can evolve in that direction.
On Mon, Jul 18, 2016 at 4:14 AM, Alexander van der Grinten
<alexander.vandergrinten@gmail.com> wrote:
> Hello Gor,
>
> thank you for taking the time to answer my comments.
>
>>> Given that having from_promise is allowing for symmetry with untyped
>>> promise, [...]
>
> Well, address() and from_address() is not strictly necessary either, right?
> It can always be replaced by the following pattern:
>
> void do_something_async(void (*callback) (void *), void *argument);
>
> /* ... */
>
> auto operator await(/* ... */) {
> struct awaitable {
> void await_suspend(coroutine_handle<> handle) {
> _handle = handle;
>
> do_something_async([] (void *argument) {
> auto self = static_cast<awaitable *>(argument);
> self->_handle.resume();
> }, this);
> // The awaitable object is alive until the
> // await-expression completes, so this is fine.
> }
>
> /* ... */
>
> coroutine_handle<> _handle;
> }
>
> return awaitable(/* ... */);
> }
>
> This pattern is more general than address() / from_address(): It allows to
> store additional parameters the callback receives in the awaitable object
> can return them from await_resume. This enables users to implement non-void
> await regardless of the underlying promise type; something which is not
> possible with address() / from_address()! Why does the proposal include an
> explicit address() / from_address() instead of promoting the use of this
> store-handle-in-awaitable pattern?
>
>>> We added await_transform in P0057R1, it can be used to do what you are
>>> suggesting.
>
> I see, this is indeed a much better idea than what I was suggesting.
>
>
> Let me ask you another question: Why does the proposal _only_ provide
> type-erased coroutine_handles? A call to resume() / done() / destroy()
> results in an indirect jump. I agree that the compiler should be able to
> devirtualize this jump in many cases; I also agree that having the
> coroutine_handle of the prosal is important. But why don't we do something
> like the following:
>
> Define a `suspend-point handle` as a type that has the same interface as
> coroutine_handle but has weaker guarantees: resume() / done() and destroy()
> must only be called while the underlying coroutine is suspended in exactly
> the same execution of the await-expression it was constructed for. Add an
> implicit conversion from each `suspend-point handle` type to
> coroutine_handle. Pass a `suspend-point handle` instead of a
> coroutine_handle to await_suspend().
>
> This way we can write await_suspend like this:
>
> template<typename H>
> void await_suspend(H handle);
> // This is specialized for each await-expression, so that the compiler
> can
> // avoid using indirect calls for resume() / done() / destory() here.
>
> void await_suspend(coroutine_handle<> handle);
> // Still works the same as before. Uses the implicit conversion to
> construct
> // a coroutine_handle<>.
>
> I feel like doing this has zero downsides. Sure, it is a code size for speed
> trade-off but it is opt-in so that await operators for commonly used types
> like std::future would still be able to use the more conservative
> coroutine_handle. It has a niche for code where the failure to devirtualize
> an indirect jump would result in a noticeable performance overhead: Consider
> using await to read from a fast in-memory cache. The fast-path of such a
> operation might be a single atomic load-acquire (aka a usual non-atomic load
> on x86_64) and a indirect call would dominate the run time of the whole
> operation. Also note that devirtualization is a relatively complex
> optimization and might not be possible in some cases (e.g. when code in a
> different translation unit is invoked and the compiler is unable to prove
> that this code does not change the target of the jump (e.g. by resuming the
> coroutine and suspending again); or just when compiling in debug mode).
> Using this technique resume() would be so fast (it would always be inlined
> and often be completely removed by an optimizing compiler) that one could
> decide to abolish await_ready.
>
> Note than in order to enable the store-handle-in-awaitable pattern from
> above together with this technique the handle would need to be passed to
> operator await (and not to await_suspend). This would allow us to convert
> existing C-style callbacks to await in a very natural way and without using
> any indirect jumps or address() magic:
>
> template<typename H>
> auto operator await(std::chrono::seconds t, H handle) {
> struct awaitable {
> awaitable(std::chrono::seconds t, H handle)
> : _t(t), _handle(handle) { }
>
> void await_suspend() {
> call_in_n_seconds(_t.count(), [] (void *argument) {
> auto self = static_cast<awaitable *>(argument);
> self->_handle.resume();
> }, this);
> }
>
> std::chrono::seconds _t;
> H _handle;
> };
>
> return awaitable(t, handle);
> }
>
> Many thanks,
> Alexander
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/sAzQqQvY6BI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c2ccd580-126c-42f0-967c-bdb9fc72f890%40isocpp.org.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAJ4Vuxsa7%3D4EBqtM%2BHSi6CGkx0UFUA8%2BTL-u1WdsVQ8DGQHh-A%40mail.gmail.com.
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Tue, 19 Jul 2016 12:18:43 -0700 (PDT)
Raw View
------=_Part_1210_1201726447.1468955923535
Content-Type: multipart/alternative;
boundary="----=_Part_1211_943589400.1468955923535"
------=_Part_1211_943589400.1468955923535
Content-Type: text/plain; charset=UTF-8
Hi Gor,
for now I'm not that interested on what can be built on top of P0057: I
really think that P0057 enables powerful abstraction and I think that it is
the correct foundation to build on.
At the moment I'm more concerned about how to build abstractions that are
as efficient as possible on top of P0057. There are two points that bug me
about P0057 in its current form but I think that both can be fixed without
changing both the wording or existing prototype implementations too much. I
do not want P0057 to change much, after all it has working implementations.
- I think we're missing an optimization opportunity by passing a
type-erased type to await_suspend.
- I want to be able to wrap C functions of the form
void do_something_async(void (*callback) (void *context, int result),
void *context)
as efficiently as possible. The problem here is that I can use
from_address() to reconstruct the coroutine_handle but I cannot access the
awaiter that needs to hold the int result.
What do you think about the following non-intrusive, hypothetical changes
to P0057?
- Change (3.5) in 5.3.8 of the paper to:
h is an object of an implementation-defined type that is implicitly
convertible to and has the same interface as std::coroutine_handle<P>
except that resume(), done() and destroy() must only be called until this
await-expression is complete.
This does allow (but not force) implementations to pass more specialized
types to await_suspend. It does not break existing implementations as
passing a coroutine_handle is still allowed.
- Allow access to the awaiter object of a suspended coroutine; maybe
overload std::get<T> for coroutine_handle<> so that it returns a reference
to the awaiter (and throws if T does not equal its type).
This allows users to store the return value of an async operation in the
awaiter object after using from_address(). It does not break code that uses
existing prototypes of P0057.
Kind regards,
Alexander
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c0467b3e-bbdd-4eda-b6d3-b2a7f57417f4%40isocpp.org.
------=_Part_1211_943589400.1468955923535
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi Gor,</div><div><br></div><div>for now I'm not =
that interested on what can be built on top of P0057: I really think that P=
0057 enables powerful abstraction and I think that it is the correct founda=
tion to build on.</div><div><br></div><div>At the moment I'm more conce=
rned about how to build abstractions that are as efficient as possible on t=
op of P0057. There are two points that bug me about P0057 in its current fo=
rm but I think that both can be fixed without changing both the wording or =
existing prototype implementations too much. I do not want P0057 to change =
much, after all it has working implementations.</div><div><br></div><div>- =
I think we're missing an optimization opportunity by passing a type-era=
sed type to await_suspend.</div><div><br></div><div>- I want to be able to =
wrap C functions of the form</div><div>=C2=A0 void do_something_async(void =
(*callback) (void *context, int result), void *context)</div><div>=C2=A0 as=
efficiently as possible. The problem here is that I can use from_address()=
to reconstruct the coroutine_handle but I cannot access the awaiter that n=
eeds to hold the int result.</div><div><br></div><div>What do you think abo=
ut the following non-intrusive, hypothetical changes to P0057?</div><div><b=
r></div><div>- Change (3.5) in 5.3.8 of the paper to:</div><div>=C2=A0 h is=
an object of an implementation-defined type that is implicitly convertible=
to and has the same interface as std::coroutine_handle<P> except tha=
t resume(), done() and destroy() must only be called until this await-expre=
ssion is complete.</div><div>=C2=A0=C2=A0</div><div>=C2=A0 This does allow =
(but not force) implementations to pass more specialized types to await_sus=
pend. It does not break existing implementations as passing a coroutine_han=
dle is still allowed.</div><div><br></div><div>- Allow access to the awaite=
r object of a suspended coroutine; maybe overload std::get<T> for cor=
outine_handle<> so that it returns a reference to the awaiter (and th=
rows if T does not equal its type).</div><div>=C2=A0=C2=A0</div><div>=C2=A0=
This allows users to store the return value of an async operation in the a=
waiter object after using from_address(). It does not break code that uses =
existing prototypes of P0057.</div><div><br></div><div>Kind regards,</div><=
div>Alexander</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/c0467b3e-bbdd-4eda-b6d3-b2a7f57417f4%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/c0467b3e-bbdd-4eda-b6d3-b2a7f57417f4=
%40isocpp.org</a>.<br />
------=_Part_1211_943589400.1468955923535--
------=_Part_1210_1201726447.1468955923535--
.
Author: Gor Nishanov <gornishanov@gmail.com>
Date: Tue, 19 Jul 2016 18:47:11 -0700
Raw View
Hi Alexander:
The first one, absolutely. I just did not get cycles to try it out and
tweaking the wording to make it legal.
For the second one, "getting an awaiter", can you give me an example
what it allows you to do that you cannot do without it.
On Tue, Jul 19, 2016 at 12:18 PM, Alexander van der Grinten
<alexander.vandergrinten@gmail.com> wrote:
> Hi Gor,
>
> for now I'm not that interested on what can be built on top of P0057: I
> really think that P0057 enables powerful abstraction and I think that it is
> the correct foundation to build on.
>
> At the moment I'm more concerned about how to build abstractions that are as
> efficient as possible on top of P0057. There are two points that bug me
> about P0057 in its current form but I think that both can be fixed without
> changing both the wording or existing prototype implementations too much. I
> do not want P0057 to change much, after all it has working implementations.
>
> - I think we're missing an optimization opportunity by passing a type-erased
> type to await_suspend.
>
> - I want to be able to wrap C functions of the form
> void do_something_async(void (*callback) (void *context, int result), void
> *context)
> as efficiently as possible. The problem here is that I can use
> from_address() to reconstruct the coroutine_handle but I cannot access the
> awaiter that needs to hold the int result.
>
> What do you think about the following non-intrusive, hypothetical changes to
> P0057?
>
> - Change (3.5) in 5.3.8 of the paper to:
> h is an object of an implementation-defined type that is implicitly
> convertible to and has the same interface as std::coroutine_handle<P> except
> that resume(), done() and destroy() must only be called until this
> await-expression is complete.
>
> This does allow (but not force) implementations to pass more specialized
> types to await_suspend. It does not break existing implementations as
> passing a coroutine_handle is still allowed.
>
> - Allow access to the awaiter object of a suspended coroutine; maybe
> overload std::get<T> for coroutine_handle<> so that it returns a reference
> to the awaiter (and throws if T does not equal its type).
>
> This allows users to store the return value of an async operation in the
> awaiter object after using from_address(). It does not break code that uses
> existing prototypes of P0057.
>
> Kind regards,
> Alexander
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/sAzQqQvY6BI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c0467b3e-bbdd-4eda-b6d3-b2a7f57417f4%40isocpp.org.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAJ4Vuxu4Dx5YyDbZg%2B1Vq9k6_WBQWJMYsXE4d7TUWsym-sPoQg%40mail.gmail.com.
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Wed, 20 Jul 2016 00:18:02 -0700 (PDT)
Raw View
------=_Part_6099_365334988.1468999082960
Content-Type: multipart/alternative;
boundary="----=_Part_6100_670888697.1468999082960"
------=_Part_6100_670888697.1468999082960
Content-Type: text/plain; charset=UTF-8
Hi Gor,
> The first one, absolutely.
Perfect :)
> For the second one, "getting an awaiter", can you give me an example what
it allows you to do that you cannot do without it.
There is a large number of C libraries (e.g. libuv, Windows IOCP, Qt
signals/slots, the Linux epoll interface) that perform async computations
and signal completion either by invoking a callback or by providing some
get_completed_events() function. Usually these libraries allow you to pass
an arbitrary word (i.e. void *) to the completion code.
Wrapping those functions to an awaitable type currently requires
workarounds (like storing the coroutine_handler in the awaiter) because you
need *two* words of state: The pointer returned from
coroutine_handle<>::address() and a pointer to the awaiter where you want
to store the result of the operation.
Consider
void do_write_async(const void *buffer, size_t size,
void (*callback) (void *context, int status), void *context);
where 'context' is passed to 'callback' as the first argument.
Lets say I want to wrap it via operator await:
auto operator await (write_async w) {
struct awaiter {
awaiter(write_async w) : _w(w) { }
void await_ready() { return false; }
int await_resume() { return _status; }
void await_suspend(std::coroutine_handle<> h) {
do_write_async(_w.buffer, _w.size, [] (void *p, int status)
{
auto h = std::coroutine_handle<>::from_address(p);
// We want to to store status in awaiter::_status, but
there is
// no way to get a reference to the awaiter!
// The suggestion is to allow
// std::get<awaiter>(handle)._status = status;
h.resume();
}, h.address());
}
write_async _w;
int _status;
};
return awaiter(w);
}
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/a75fa022-ed21-499c-98b1-60db3ea54a4c%40isocpp.org.
------=_Part_6100_670888697.1468999082960
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>Hi Gor,</div><div><br></div><div>> The first one, =
absolutely.</div><div><br></div><div>Perfect :)</div><div><br></div><div>&g=
t; For the second one, "getting an awaiter", can you give me an e=
xample what it allows you to do that you cannot do without it.</div><div><b=
r></div><div>There is a large number of C libraries (e.g. libuv, Windows IO=
CP, Qt signals/slots, the Linux epoll interface) that perform async computa=
tions and signal completion either by invoking a callback or by providing s=
ome get_completed_events() function. Usually these libraries allow you to p=
ass an arbitrary word (i.e. void *) to the completion code.</div><div><br><=
/div><div>Wrapping those functions to an awaitable type currently requires =
workarounds (like storing the coroutine_handler in the awaiter) because you=
need *two* words of state: The pointer returned from coroutine_handle<&=
gt;::address() and a pointer to the awaiter where you want to store the res=
ult of the operation.</div><div><br></div><div>Consider</div><div>=C2=A0 =
=C2=A0 void do_write_async(const void *buffer, size_t size,</div><div>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 void (*callback) (void *context, int status), void=
*context);</div><div>where 'context' is passed to 'callback=
9; as the first argument.</div><div><br></div><div>Lets say I want to wrap =
it via operator await:</div><div><br></div><div>=C2=A0 =C2=A0 auto operator=
await (write_async w) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct await=
er {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 awaiter(write_asyn=
c w) : _w(w) { }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0<=
/div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await_ready() { re=
turn false; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int await=
_resume() { return _status; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await=
_suspend(std::coroutine_handle<> h) {</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 do_write_async(_w.buffer, _w.size, [] (v=
oid *p, int status) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 auto h =3D std::coroutine_handle<>::from_=
address(p);</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 // We want to to store status in awaiter::_sta=
tus, but there is</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 // no way to get a reference to the awaiter!</div>=
<div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
// The suggestion is to allow</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // std::get<awaiter>(handle)._stat=
us =3D status;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 h.resume();</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }, h.address());</div><div>=C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 write_asy=
nc _w;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int _status;</di=
v><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return awaiter(w);</div><div>=
=C2=A0 =C2=A0 }</div><div><br></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/a75fa022-ed21-499c-98b1-60db3ea54a4c%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/a75fa022-ed21-499c-98b1-60db3ea54a4c=
%40isocpp.org</a>.<br />
------=_Part_6100_670888697.1468999082960--
------=_Part_6099_365334988.1468999082960--
.
Author: gluk.ua@gmail.com
Date: Fri, 22 Jul 2016 11:44:28 -0700 (PDT)
Raw View
------=_Part_1335_1057711965.1469213068645
Content-Type: multipart/alternative;
boundary="----=_Part_1336_1717524533.1469213068645"
------=_Part_1336_1717524533.1469213068645
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Hi Alexander,
Will the following work for your example ?
auto operator await (write_async w) {
struct awaiter {
awaiter(write_async w) : _w(w) { }
=20
void await_ready() { return false; }
int await_resume() { return _status; }
=20
void await_suspend(std::coroutine_handle<> h) {
_awaitingHandle =3D std::move(h);
do_write_async(_w.buffer, _w.size, resumeCb, this);
}
static void resumeCb(void* ptr, int status) {
reinterpret_cast<awaiter*>(ptr)->resume(status);
}
void resume(int status) {
_status =3D status;
_awaitingHandle.resume();
}
=20
write_async _w;
int _status;
std::coroutine_handle<> _awaitingHandle;
};
=20
return awaiter(w);
}
Thanks,
Andrii
=D1=81=D0=B5=D1=80=D0=B5=D0=B4=D0=B0, 20 =D0=BB=D0=B8=D0=BF=D0=BD=D1=8F 201=
6 =D1=80. 00:18:03 UTC-7 =D0=BA=D0=BE=D1=80=D0=B8=D1=81=D1=82=D1=83=D0=B2=
=D0=B0=D1=87 Alexander van der=20
Grinten =D0=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=B2:
>
> Hi Gor,
>
> > The first one, absolutely.
>
> Perfect :)
>
> > For the second one, "getting an awaiter", can you give me an example=20
> what it allows you to do that you cannot do without it.
>
> There is a large number of C libraries (e.g. libuv, Windows IOCP, Qt=20
> signals/slots, the Linux epoll interface) that perform async computations=
=20
> and signal completion either by invoking a callback or by providing some=
=20
> get_completed_events() function. Usually these libraries allow you to pas=
s=20
> an arbitrary word (i.e. void *) to the completion code.
>
> Wrapping those functions to an awaitable type currently requires=20
> workarounds (like storing the coroutine_handler in the awaiter) because y=
ou=20
> need *two* words of state: The pointer returned from=20
> coroutine_handle<>::address() and a pointer to the awaiter where you want=
=20
> to store the result of the operation.
>
> Consider
> void do_write_async(const void *buffer, size_t size,
> void (*callback) (void *context, int status), void *context);
> where 'context' is passed to 'callback' as the first argument.
>
> Lets say I want to wrap it via operator await:
>
> auto operator await (write_async w) {
> struct awaiter {
> awaiter(write_async w) : _w(w) { }
> =20
> void await_ready() { return false; }
> int await_resume() { return _status; }
> =20
> void await_suspend(std::coroutine_handle<> h) {
> do_write_async(_w.buffer, _w.size, [] (void *p, int=20
> status) {
> auto h =3D std::coroutine_handle<>::from_address(p);
> =20
> // We want to to store status in awaiter::_status, bu=
t=20
> there is
> // no way to get a reference to the awaiter!
> // The suggestion is to allow
> // std::get<awaiter>(handle)._status =3D status;
> =20
> h.resume();
> }, h.address());
> }
> =20
> write_async _w;
> int _status;
> };
> =20
> return awaiter(w);
> }
>
>
--=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.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/1cd21f4d-49b2-4c5b-999f-b53438f02bb2%40isocpp.or=
g.
------=_Part_1336_1717524533.1469213068645
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">Hi Alexander,<div><br></div><div>Will the following work f=
or your example ?</div><div><br></div><div><div>=C2=A0=C2=A0 auto operator =
await (write_async w) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct awaite=
r {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 awaiter(write_async=
w) : _w(w) { }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</=
div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await_ready() { ret=
urn false; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int await_=
resume() { return _status; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await=
_suspend(std::coroutine_<wbr>handle<> h) {</div><div>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 _awaitingHandle =3D std::move(h);=
</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 do_write=
_async(_w.buffer, _w.size, resumeCb, this);</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 }</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 static void resumeCb(void* ptr, int status) {</div><div>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 reinterpret_cast<aw=
aiter*>(ptr)->resume(status);<br>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 }</div><div><br></div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
void resume(int status) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 _status =3D status;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 _awaitingHandle.resume();</div><div>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 write_=
async _w;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int _status;<=
/div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 std::coroutine_<wbr>han=
dle<> _awaitingHandle;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</div>=
<div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=
=A0 return awaiter(w);</div><div>=C2=A0 =C2=A0 }</div><div><br></div><div>T=
hanks,</div><div>Andrii</div><br>=D1=81=D0=B5=D1=80=D0=B5=D0=B4=D0=B0, 20 =
=D0=BB=D0=B8=D0=BF=D0=BD=D1=8F 2016 =D1=80. 00:18:03 UTC-7 =D0=BA=D0=BE=D1=
=80=D0=B8=D1=81=D1=82=D1=83=D0=B2=D0=B0=D1=87 Alexander van der Grinten =D0=
=BD=D0=B0=D0=BF=D0=B8=D1=81=D0=B0=D0=B2:<blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div dir=3D"ltr"><div>Hi Gor,</div><div><br></div><div>> The f=
irst one, absolutely.</div><div><br></div><div>Perfect :)</div><div><br></d=
iv><div>> For the second one, "getting an awaiter", can you gi=
ve me an example what it allows you to do that you cannot do without it.</d=
iv><div><br></div><div>There is a large number of C libraries (e.g. libuv, =
Windows IOCP, Qt signals/slots, the Linux epoll interface) that perform asy=
nc computations and signal completion either by invoking a callback or by p=
roviding some get_completed_events() function. Usually these libraries allo=
w you to pass an arbitrary word (i.e. void *) to the completion code.</div>=
<div><br></div><div>Wrapping those functions to an awaitable type currently=
requires workarounds (like storing the coroutine_handler in the awaiter) b=
ecause you need *two* words of state: The pointer returned from coroutine_h=
andle<>::address() and a pointer to the awaiter where you want to sto=
re the result of the operation.</div><div><br></div><div>Consider</div><div=
>=C2=A0 =C2=A0 void do_write_async(const void *buffer, size_t size,</div><d=
iv>=C2=A0 =C2=A0 =C2=A0 =C2=A0 void (*callback) (void *context, int status)=
, void *context);</div><div>where 'context' is passed to 'callb=
ack' as the first argument.</div><div><br></div><div>Lets say I want to=
wrap it via operator await:</div><div><br></div><div>=C2=A0 =C2=A0 auto op=
erator await (write_async w) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 struct=
awaiter {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 awaiter(writ=
e_async w) : _w(w) { }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 void await_ready=
() { return false; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 in=
t await_resume() { return _status; }</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 voi=
d await_suspend(std::coroutine_<wbr>handle<> h) {</div><div>=C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 do_write_async(_w.buffer, =
_w.size, [] (void *p, int status) {</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 auto h =3D std::coroutine_handle&=
lt;>::from_<wbr>address(p);</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // We want to to store sta=
tus in awaiter::_status, but there is</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // no way to get a reference to =
the awaiter!</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 // The suggestion is to allow</div><div>=C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 // std::get<awaiter=
>(handle)._<wbr>status =3D status;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 h.resume();</div><d=
iv>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }, h.address());=
</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }</div><div>=C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 =C2=A0 write_async _w;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
=C2=A0 int _status;</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 };</div><div>=C2=
=A0 =C2=A0 =C2=A0 =C2=A0=C2=A0</div><div>=C2=A0 =C2=A0 =C2=A0 =C2=A0 return=
awaiter(w);</div><div>=C2=A0 =C2=A0 }</div><div><br></div></div></blockquo=
te></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/1cd21f4d-49b2-4c5b-999f-b53438f02bb2%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/1cd21f4d-49b2-4c5b-999f-b53438f02bb2=
%40isocpp.org</a>.<br />
------=_Part_1336_1717524533.1469213068645--
------=_Part_1335_1057711965.1469213068645--
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Fri, 22 Jul 2016 15:17:11 -0700 (PDT)
Raw View
------=_Part_656_60794628.1469225832093
Content-Type: multipart/alternative;
boundary="----=_Part_657_636712700.1469225832093"
------=_Part_657_636712700.1469225832093
Content-Type: text/plain; charset=UTF-8
> Will the following work for your example ?
That does work but I consider it a clunky workaround.
* It defeats the purpose of from_address(). The *only* use of
from_address() is wrapping C functions. The from_address() mechanism is of
questionale usefulness if it can only wrap C functions do not return async
results.
* If storing a coroutine_handle<> in the awaiter is common practice then
coroutine_handle<> should be passed to the constructor of the awaiter and
not to its member function. That however is a more invasive change and
would render current prototypes non-conforming; providing a way to access
the awaiter does not.
* If non-type-erased handles were implemented this workaround would yield
suboptimal performance as it requires two indirect jumps instead of one in
that situation.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/4ccbcd9f-dd8d-4316-a09a-03331d7738c4%40isocpp.org.
------=_Part_657_636712700.1469225832093
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div><div>> Will the following work for your example ?<=
/div><div><br></div><div>That does work but I consider it a clunky workarou=
nd.</div><div><br></div><div>* It defeats the purpose of from_address(). Th=
e *only* use of from_address() is wrapping C functions. The from_address() =
mechanism is of questionale usefulness if it can only wrap C functions do n=
ot return async results.</div><div><br></div><div>* If storing a coroutine_=
handle<> in the awaiter is common practice then coroutine_handle<&=
gt; should be passed to the constructor of the awaiter and not to its membe=
r function. That however is a more invasive change and would render current=
prototypes non-conforming; providing a way to access the awaiter does not.=
</div><div><br></div><div>* If non-type-erased handles were implemented thi=
s workaround would yield suboptimal performance as it requires two indirect=
jumps instead of one in that situation.</div></div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/4ccbcd9f-dd8d-4316-a09a-03331d7738c4%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/4ccbcd9f-dd8d-4316-a09a-03331d7738c4=
%40isocpp.org</a>.<br />
------=_Part_657_636712700.1469225832093--
------=_Part_656_60794628.1469225832093--
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Fri, 22 Jul 2016 15:31:44 -0700 (PDT)
Raw View
------=_Part_1220_253691992.1469226704258
Content-Type: multipart/alternative;
boundary="----=_Part_1221_1971427837.1469226704258"
------=_Part_1221_1971427837.1469226704258
Content-Type: text/plain; charset=UTF-8
>If non-type-erased handles were implemented this workaround would yield
suboptimal performance as it requires two indirect jumps instead of one in
that situation.
Thinking about it the pattern works even in this case if one does not store
the handle in the awaiter but the address(). So basically all boils down to:
Does a more straightforward way to wrap C functions justify the
implementation of an awaiter accessor function?
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dcc846ed-46cf-44bf-95e0-7d48576bcdf4%40isocpp.org.
------=_Part_1221_1971427837.1469226704258
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">>If non-type-erased handles were implemented this worka=
round would yield suboptimal performance as it requires two indirect jumps =
instead of one in that situation.<div><br></div><div>Thinking about it the =
pattern works even in this case if one does not store the handle in the awa=
iter but the address(). So basically all boils down to:</div><div><br></div=
><div>Does a more straightforward way to wrap C functions justify the imple=
mentation of an awaiter accessor function?</div></div>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/dcc846ed-46cf-44bf-95e0-7d48576bcdf4%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/dcc846ed-46cf-44bf-95e0-7d48576bcdf4=
%40isocpp.org</a>.<br />
------=_Part_1221_1971427837.1469226704258--
------=_Part_1220_253691992.1469226704258--
.
Author: Gor Nishanov <gornishanov@gmail.com>
Date: Fri, 22 Jul 2016 15:57:33 -0700
Raw View
I am not sure I understand your point here. You don't need two indirect jumps.
You wanted a non-type erased coroutine_handle, so that you can
synthesize a callback function that will perform a direct call to
resume(). Well, just pass an address of an awaiter as a context and
store coroutine_handle<> or void* in your awaiter.
Modifying slightly Andrii's example, gets you what you want:
auto operator await (write_async w) {
struct awaiter {
awaiter(write_async w) : _w(w) { }
void await_ready() { return false; }
int await_resume() { return _status; }
template <typename Promise>
void await_suspend(std::coroutine_handle<Promise> h) {
_awaitingHandle = h.address();
do_write_async(_w.buffer, _w.size, [](void* ptr, int status) {
auto me = reinterpret_cast<awaiter*>(ptr);
me->_status = status;
std::coroutine_handle<Promise>::from_address(me->_awaitingHandle);
},
this);
}
write_async _w;
int _status;
void* _awaitingHandle;
};
return awaiter(w);
}
On Fri, Jul 22, 2016 at 3:31 PM, Alexander van der Grinten
<alexander.vandergrinten@gmail.com> wrote:
>>If non-type-erased handles were implemented this workaround would yield
>> suboptimal performance as it requires two indirect jumps instead of one in
>> that situation.
>
> Thinking about it the pattern works even in this case if one does not store
> the handle in the awaiter but the address(). So basically all boils down to:
>
> Does a more straightforward way to wrap C functions justify the
> implementation of an awaiter accessor function?
>
> --
> You received this message because you are subscribed to a topic in the
> Google Groups "ISO C++ Standard - Future Proposals" group.
> To unsubscribe from this topic, visit
> https://groups.google.com/a/isocpp.org/d/topic/std-proposals/sAzQqQvY6BI/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> std-proposals+unsubscribe@isocpp.org.
> To post to this group, send email to std-proposals@isocpp.org.
> To view this discussion on the web visit
> https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dcc846ed-46cf-44bf-95e0-7d48576bcdf4%40isocpp.org.
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAJ4Vuxuuf_jnBqCSDm%3D%2BG2qqmy0m5eTBiE7-a9Ac_W58U6WGqw%40mail.gmail.com.
.
Author: Alexander van der Grinten <alexander.vandergrinten@gmail.com>
Date: Fri, 22 Jul 2016 16:48:56 -0700 (PDT)
Raw View
------=_Part_1246_162352117.1469231336917
Content-Type: multipart/alternative;
boundary="----=_Part_1247_81027270.1469231336918"
------=_Part_1247_81027270.1469231336918
Content-Type: text/plain; charset=UTF-8
> Modifying slightly Andrii's example, gets you what you want
Yes, you're right. I overlooked that possibility. That makes "getting an
awaiter" a luxury feature that arguably should not be added to the proposal.
Thanks again for your comments. I'm looking forward to see if
non-type-erased handles make it to a future revision of the paper :)
--
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.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/93e28ba6-2250-4db0-83ed-afccafde31e6%40isocpp.org.
------=_Part_1247_81027270.1469231336918
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>> Modifying slightly Andrii's example, gets yo=
u what you want</div><div><br></div><div>Yes, you're right. I overlooke=
d that possibility. That makes "getting an awaiter" a luxury feat=
ure that arguably should not be added to the proposal.</div><div><br></div>=
<div>Thanks again for your comments. I'm looking forward to see if non-=
type-erased handles make it to a future revision of the paper :)</div></div=
>
<p></p>
-- <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 />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/93e28ba6-2250-4db0-83ed-afccafde31e6%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/93e28ba6-2250-4db0-83ed-afccafde31e6=
%40isocpp.org</a>.<br />
------=_Part_1247_81027270.1469231336918--
------=_Part_1246_162352117.1469231336917--
.