Re:Await in Rust
by gpderetta on Tuesday August 13, 2019 @07:52AM
(#20684829)
Oh, not at all, I want the compiler to do the CPS transform for me (same as for yield/await) and then hand me the incoming continuation as a first class lexically scoped parameter.
For example: convert an internal iterator to an external one (in pseudo C++, yes, yes, I know):
// This is a bog standard template function. Cont can be anything
// here as long as it is callable. It literally does the same thing
// as for_each
template<class Cont, class Iter>
Cont inside_out(Iter begin, Iter end, Cont yield){
// as long as yield lifetime is confined to the scope of
// inside_out; when Cont
// ends up being some compiler internal (possibly unique) magic
// type it should be possible to CPS convert both inside_out and
// for_each. Both rust and C++ monomorphize templates anyway so
// instantiating dedicated CPS variant is not a problem.
std::for_each(begin, end, [&](auto&& x) { yield(x); });
// for various reasons we need to return the continuation here. A
// proper language would tail call to it.
return yield;
}
...
// this is basically call/cc. It uses magic to get the current
// continuation, then invokes its first argument with it and the
// remaining arguments. The current function need to be
// Note: template functions are not first class in
// C++, but we take some liberty here.
auto cont = continuationify(inside_out, my_vec.begin(), y_vec.end());
while(not cont.done())
std::cout << cont();
if inside_out was not templated, but instead Cont was type erased (a trait object in rust parlance), then continuatinify would need to allocate a dedicated stack and fall back to good old userspace context switching (the compiler is welcome to pierce through the type erasure layer and optimize anyway, but it would not be a guaranteed optimization).
Rust is close enough to C++ that it would work in the same way. I've been planning to write a paper for the C++ committee to add fire to the current coroutine controversy and proposing something like the above (which would unify stackless and stackful coroutines).
For example: convert an internal iterator to an external one (in pseudo C++, yes, yes, I know):
if inside_out was not templated, but instead Cont was type erased (a trait object in rust parlance), then continuatinify would need to allocate a dedicated stack and fall back to good old userspace context switching (the compiler is welcome to pierce through the type erasure layer and optimize anyway, but it would not be a guaranteed optimization).Rust is close enough to C++ that it would work in the same way. I've been planning to write a paper for the C++ committee to add fire to the current coroutine controversy and proposing something like the above (which would unify stackless and stackful coroutines).