On the semantic side, extending it to a N:M threading model like Erlang or Go would work great. But that model only seems to work well if you basically make the entire language async, which is in conflict with too many of rust's goals. So we are left with the somewhat awkward state of async as a second class citizen.
How does go nest aync calls?
func f() { }
func g() { }
func h() { go g() go f() }
What happens on
f()
Are the g() and f() calls inside h() blocking? Or are they async and the block happens at the point of return? Which would be the main difference to languages with an async keyword, were you need to be explicit about blocking.
f()
is a sync call to the function f, and the function f used async calls inside. Somewhere then needs to be a transition from async to sync contexts (aka wait/block).
I wondered where this happens.
From your comment I assume there is a difference, in sync code I would do
x = f()
while in async code I would use
f(channel)
?
func f(ch chan[int]) {
ch <- 1 // depending on the channel implementation this is a blocking action
}
then I can call that function asynchronously go f(ch)
and later when I want the value from f I can retrieve it from the channel i := <-ch // this is a blocking call
The net effect of the all the above is that async and non async code is highly composable. if I have a function that computes a value and I want to get that value asynchronously then I can wrap it in a function that uses a channel to get the value to me. go func() { ch<-f() }
Every function is a potential asynchronous function.How does this differ from Rust (Or Typescript etc.) where we would use
async f() -> i32 { }
fn g() { f().wait() }
to block?