Announcement

Collapse
No announcement yet.

Rust 1.39 Released With Async-Await Support, Attributes On Function Parameters

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • mmstick
    replied
    Originally posted by cynical View Post

    First of all, futures and promises are exactly the same thing, in that promise is just another name for a future. Rust futures, however, have an absolutely hideous syntax. I can see why async/await is a godsend here. In JavaScript, promises are actually easier to understand (imo) and nicer than async/await because I actually WANT an obvious syntactic difference between async/sync code. When I see a chain of thens, I know I am dealing with an asynchronous pipeline. I can continue to chain them as long as I want, and the error handling will deal with anything that bubbles up in the process.

    As for an example in JS:
    Code:
    grabUserFromDB(username)
    .then(getFriends)
    .then(getHealthRecords)
    .catch(err => processErr);
    Absolutely trivial, beautiful code. And of course if your functions are rather short you can simply inline them in this fashion:

    Code:
    grabUserFromDB(username)
    .then(user => user.name.toUpperCase())
    .catch(err => processErr);

    The same is also possible of futures in Rust. See the FutureExt then method in the futures crate.

    The problem is that this can often create a deeply nested spaghetti monster if you try to do anything sufficiently complex. In addition to being harder to read and write for a newcomer to async, there are also some patterns which can't be represented safely here, and the generated state machines can get quite complex. Using the async await syntax, this gives the compiler an edge to reduce the generate state machines to much smaller, more efficient structures. It also opens the door to some patterns which previously weren't compatible with the functional approach, without resorting to heap allocations and reference counters. async / await-generated state machines can comfortably work entirely from the stack.

    Code:
    let scope = async {
        grab_user_from_db(&username)
            .await?
            .get_friends()
            .await?
            .get_health_records()
            .await
    };
    
    if let Err(why) = scope.await {
        process_err(why);
    }
    Achieves the same effect in a way that is functional, but without requiring deeply nested functional callbacks, and generates more efficient machine code.

    Leave a comment:


  • cynical
    replied
    Originally posted by mmstick View Post

    Do you have any examples? Everything I've seen demonstrates they're no different from composing futures in Rust pre-async/await, which was a composability nightmare for anything more complex than a small demo.
    First of all, futures and promises are exactly the same thing, in that promise is just another name for a future. Rust futures, however, have an absolutely hideous syntax. I can see why async/await is a godsend here. In JavaScript, promises are actually easier to understand (imo) and nicer than async/await because I actually WANT an obvious syntactic difference between async/sync code. When I see a chain of thens, I know I am dealing with an asynchronous pipeline. I can continue to chain them as long as I want, and the error handling will deal with anything that bubbles up in the process.

    As for an example in JS:
    Code:
    grabUserFromDB(username)
      .then(getFriends)
      .then(getHealthRecords)
      .catch(err => processErr);
    Absolutely trivial, beautiful code. And of course if your functions are rather short you can simply inline them in this fashion:

    Code:
    grabUserFromDB(username)
      .then(user => user.name.toUpperCase())
      .catch(err => processErr);

    Leave a comment:


  • Guest
    Guest replied
    Originally posted by mmstick View Post

    Do you have any examples? Everything I've seen demonstrates they're no different from composing futures in Rust pre-async/await, which was a composability nightmare for anything more complex than a small demo.
    Writing these on a loonix shitposting forum is pointless, so consider that a no. It requires a good grasp on monads to use Promise efficiently, and nowadays I'm not in the mood to put up with ECMA-262 without getting paid. There are lots of more fun languages that I can spend my time writing in.

    Leave a comment:


  • mmstick
    replied
    Originally posted by DoMiNeLa10 View Post

    Take a look at a pseudo monadic approach like Promise from ES2015, where you don't need to nest things to have a complex chain of async operations. It's much cleaner than async/await.
    Do you have any examples? Everything I've seen demonstrates they're no different from composing futures in Rust pre-async/await, which was a composability nightmare for anything more complex than a small demo.

    Leave a comment:


  • Guest
    Guest replied
    Originally posted by mmstick View Post

    In what way would callbacks be cleaner here? Callbacks were how futures were created before async/await, and it was a catastrophe to compose and maintain.
    Take a look at a pseudo monadic approach like Promise from ES2015, where you don't need to nest things to have a complex chain of async operations. It's much cleaner than async/await.

    Leave a comment:


  • mmstick
    replied
    Originally posted by DoMiNeLa10 View Post

    With a monadic approach you just use callbacks, and your code becomes MUCH cleaner. You don't need to write awkward error handling code, and your code will become pretty short.
    In what way would callbacks be cleaner here? Callbacks were how futures were created before async/await, and it was a catastrophe to compose and maintain.

    Leave a comment:


  • xnor
    replied
    @Anarchy: it's supposed to be simple, that way you have minimal overhead.
    You can still build actor model frameworks in rust, but I see no reason to include that directly in the language.

    Leave a comment:


  • Anarchy
    replied
    Hm... async/await is nice but it's just (simple) concurrent programming. I was really hoping they'd bring the actor model to Rust as a way to do concurrent and parallel computing, the language is already functional and should lend itself very well to it.
    Last edited by Anarchy; 09 November 2019, 10:36 AM.

    Leave a comment:


  • xnor
    replied
    Some guys here are confusing multi-threading with asynchronicity. Asynchronous code can still be single-threaded.

    The idea behind asynchronous code is to not block the CPU pointlessly waiting for some result (e.g. of an I/O operation) when you could continue doing other, actually useful things.

    Leave a comment:


  • Guest
    Guest replied
    Originally posted by mmstick View Post

    The way it's been implemented in Rust is virtually no different from writing traditional synchronous functions. Error handling is no different than before. The only difference between async and non-async code is the use of the `.await` postfix to begin execution of a future. Unless you start joining futures and spawning tasks, it will execute no differently than traditional synchronous code.

    The below async code:

    Code:
    let mut buf = String::new();
    File::open(path)
    .await
    .context("failed to open file")?
    .read_to_string(&mut buf)
    .await
    .context("failed to read file");
    Is the same as the identical sync code, minus not being given a choice on how to await a result.

    Code:
    let mut buf = String::new();
    File::open(path)
    .context("failed to open file")?
    .read_to_string(&mut buf)
    .context("failed to read file");
    At least with async, you can poll many tasks simultaneously, instead of waiting for one task to complete before beginning the next.
    With a monadic approach you just use callbacks, and your code becomes MUCH cleaner. You don't need to write awkward error handling code, and your code will become pretty short.

    Leave a comment:

Working...
X