News for hackers. Stuff that matters.
Re:Async and Await in Rust: a full proposal by infogulch on Sunday July 15, 2018 @05:23PM (#17537162)
I think it should be possible to design an async system that is generically async, i.e. whether a given function with no special annotations or syntax is async (including all of the async-able calls that function makes transitively) is entirely determined by the top-level caller at compile time. The called function doesn't need any special syntax, and in fact doesn't even need to consider being async at all: the async-capability bubbles up based on what other async-able functions it calls. Only the very ends of the chain: at the bottom doing IO via system calls, or at the very top where request handlers are first dispatched (for example) should need to think about being asynchronous or synchronous at all; everything in-between is compiled for whatever the top wants.
Re:Async and Await in Rust: a full proposal by gpderetta on Sunday July 15, 2018 @06:37PM (#17537490)
To allow for separate compilation you need to compile each function twice though: a CPS version and 'classic' one. This can be wasteful. You also need annotations in the object file to describe the frame size of each CPS function. At some point this was seriously considered for C++ and I'm sure some language implementations actually do it.

Or you go with cactus stacks which have their own set of issues.

Re:Async and Await in Rust: a full proposal by infogulch on Sunday July 15, 2018 @07:47PM (#17537769)
> you need to compile each function twice ... This can be wasteful.

More wasteful than writing each function twice? See C# for endless examples of libraries that have manual duplicate X() and XAsync() for every single method. If you compare the two they're almost always have the exact same body, except the async version has "async" and "await" peppered in and calls duplicate XAsync methods (which are implemented the same, except they call XAsync methods... you might be seeing a pattern here).

If I'm not mistaken most rust doesn't use separate compilation and is built from source. In this case the compiler can treat it just like normal generics and just not compile it until it's used. And even with separate compilation for, e.g. a library, a very basic LTO would trivially trim out the unused methods when compiled into a final binary. And if you don't want 2x library itself, even then you can just use an escape hatch to turn it of on the crate/impl/function level and it's still better for you than the status-quo where you have to manually add a bunch of tokens and junk that the compiler already knows how to do precisely.

If anything is wasted it's human effort because we're wasting our time doing something the computer can do better and faster.

> "annotations in the object file to describe the frame size"

Wouldn't you need this anyway for anything async, even if it's manual? This seems like an argument against async in general, not automatic async.

Re:Async and Await in Rust: a full proposal by gpderetta on Sunday July 15, 2018 @08:25PM (#17537886)
I quite dislike the current async trend, so you do not have to sell me the alternatives. I was just describing the status quo.

I think that a good compromise would be implicitly inferring the 'async-ness' of template functions instantiation (or whatever they are called in your language of choice) based on a magic continuation parameter, which would also go around the separate compilation issue (assuming the language does generic monomorphization).

Re:Async and Await in Rust: a full proposal by infogulch on Sunday July 15, 2018 @09:28PM (#17538118)
Right, that's exactly how I would expect this to be implemented. The lowest-level IO functions (at the level of making syscalls) mark themselves as supporting async: e.g. "asyncable" which means it can be called either sync or async (which may actually be implemented with different os apis). Every function that calls one of these functions sees the results directly as if it were syncronous but is also marked as "asyncable". This "mark" continues up the call chain, completely transparently to the users (unless they use an escape hatch). Near the very top of the program, the main function, an main event loop, your http server thread, etc, the code chooses to call the first function either synchronously or asynchronously and decide details like which executor to use. If your "main" function calls it async, the entire call stack is compiled to use the async versions, all the way down to the syscall functions

The point is that only at the very top of the call stack or the very bottom should you ever need to care or think about whether code is async, because 99% of the time (every bit of code between main and syscalls... which is almost all of it) that's the only place you should need to care. This can be completely automatic because the compiler already knows where to insert await/async, it only needs to know when to use async (decided by main) and what to call at the end (decided by the syscall funcs).

Re:Async and Await in Rust: a full proposal by staticassertion on Sunday July 15, 2018 @08:27PM (#17537891)
I don't think you'd need to have two versions.

If I have a sync function and I call something async, I should be able to just .wait() it, I think, and get the sync behavior.

Re:Async and Await in Rust: a full proposal by gpderetta on Monday July 16, 2018 @04:26AM (#17539613)
Technically you do not, as you pointed out you can use the cps version for everything, but it is suboptimal, especially for interoperability with other languages and the os.
Re:Async and Await in Rust: a full proposal by drb91 on Sunday July 15, 2018 @07:22PM (#17537673)
You’d still need to specify and/or have a default executer, neither of which are trivial tasks to design. Somewhat ironically, the go runtime is the closest to this and has the most explicit invocation of async behavior of the languages that have seriously tried to tackle this problem.