3 ms·
> The part they are missing from async/await is the ability to easily get return values without messaging, and do this recursively for a large tree of functions
by jeremyjh 6y ago
> The part they are missing from async/await is the ability to easily get return values without messaging, and do this recursively for a large tree of functions.
No, they do not. In Elixir for example if I call:
bytes = File.read!("filename.txt")
`bytes` will have the data returned from the function call immediately, with no need for message passing or awaiting the result. Under the hood, it is still asynchronous evented I/O. If I want to explicitly await for flow control reasons (await all of or one of multiple events) that is available in the stdlib in the `Task` module. E.g.
t1 = Task.async(fn -> do_this_thing() end)
t2 = Task.async(fn -> do_this_other_thing() end)
Task.await_many([t1, t2])
You can accomplish most things without ever calling send/receive or writing your own gen_server etc.
- justsomeuser 6y agoI see, I did not know that. Last time I used Erlang (pre-Elixir), the `bytes` example would require you to set up a request/response with a blocking `receive`.
- justsomeuser 6y agoAlthough this emulates async/await (AA), under the the "async" emulated functions is message passing that must keep track of the connection between requests and responses at runtime (E.g. with state mapping request ids to response ids). I think the key issue is that the inputs and outputs are disconnected in the static program text (and only connected dynamically at runtime). Two contexts that matter for understanding how a system transitions between states are: 1. Program editing/reading. 2. Runtime. I think AA is superior for understanding the system as a whole in both these contexts, because at edit time the IDE jump to def/show all usages allows you to understand every function that will be called, and at runtime you can get a stack trace to understand where the current function came from, and where it is going. With message passing runtimes, both 1 and 2 require extra mental models on the part of the programmer, because they also need to understand the network topology (which either is not possible statically, or requires extra tooling on top of functions). Message passing breaks down your system into CSP's, which makes it easy to understand each sync process, but hard to understand the whole system, as the same program-writing-process that allowed you to break down your components is working against you when you need to put them together again to understand the whole system. I could be wrong as I have not used modern IDE's or debugging tools with message passing runtimes lately.