What about adding async/await? #2051
Replies: 5 comments 18 replies
-
Hello! Thanks for the suggestion! JavaScript is like Rust in that it has the function colouring problem. Erlang is like Go in that its concurrency doesn't result in function colouring, so you don't have to worry about whether a function of synchronous or not. Because of this and our commitment to interop Gleam has coloured functions when compiled to JavaScript, but not when compiled to Erlang. This is an annoyance as certain kinds of code can't be shared between the two targets, but it is a good trade off because we get colourless functions when possible, without sacrificing interop or performance on the JavaScript target. Having async/await in the language would unfortunately not remove the function colouring problem, instead it would likely make it worse as the future or promise type would need to be included into the core of the language, making it possible for function colouring to infect the Erlang target too. As well as all the usual problems of function colouring it would also make interop with Erlang/OTP impossible, and we would lose its actor model. async/await is a convenience to write |
Beta Was this translation helpful? Give feedback.
-
Thank you, @lpil What I meant is not introducing the promise type. await can be seen as not awaiting a value, but as calling an async function. Let's suppose you cannot instantiate a promise without immediately awaiting it, that would result in a compiler error. Since there is not a special type for a regular function call, there probably shouldn't be Promise type. It's like you call a function with special color that can call both "special-color" functions and regular functions. For Erlang those two kinds of functions could be pretty much the same. |
Beta Was this translation helpful? Give feedback.
-
We can't do concurrency with what I propose, that's right. Kind of aligns with the actor model, doesn't it? Actors do things sequentially. To do concurrency we would need some help from the runtime - some notion of the logical process we are currently in. In the case of Javascript that could be the parent coroutine, in the case of Erlang - the process. Something like this can make things execute concurrently:
What I propose is to annotate i/o related calls with async and await in the gleam code everywhere, so we won't need to guess which function is async. We can do what we want with this information, including just ignoring it. Or maybe I just didn't get what you meant in the second part. |
Beta Was this translation helpful? Give feedback.
-
@lpil I actually don't see auto-awaiting as a solution and don't have good suggestions for the example with a higher-order function. I understand why you want to go with the auto-awaiting: async-await is not needed by the Erlang target. And I think I have a good idea on this: it can be made optional! Async-await can be used for code that is common between the targets: the standard library, for example. The code targeting BEAM will be able to omit async-await (and even advised to do so). The async-await annotations can be just like types - optional. So here is the picture I can imagine:
What are the downsides to this? Btw, speaking of the semantics of async-await:
Yes, usually you can provide a custom Promise or Awaitable to wait on. I don't agree it is the default. The default is still the sequential execution: because it is the simplest and problem-free (concurrent execution brings a bag of problems even for a one-threaded runtime). By not providing the promises we just make things simpler and the rules stricter. Which can only be a good thing. |
Beta Was this translation helpful? Give feedback.
-
Well, not always does user need to write universal code like list.map. When user needs to do so he may write
or specify that in the function definition
If user is targeting Erlang he doesn't have to bother, if he is targeting js, he may specify the function has to be of async type:
|
Beta Was this translation helpful? Give feedback.
-
I am sure I'm not the first to ask about it, but I searched existing discussions by both async and await - nothing!
Imho, this is a good choice for a typed language, because, by annotating a function with "async" keyword, we can state the function is of an async type.
Also, having colored functions is less of an issue for async-only runtimes like Erlang or Javascript. It is more painful in languages like Rust, which allows both blocking and async i/o, and people can't easily reuse the code between those two.
If we try to use the "use" keyword for that purpose, it's like we get all the drawbacks without the benefits, because now our functions are colored, and we still need to pass callbacks as arguments.
What are the drawbacks / challenges to this?
Beta Was this translation helpful? Give feedback.
All reactions