from Hacker News

Show HN: Async UI: A Rust UI Library Where Everything is a Future

by wishawa on 10/5/22, 12:14 AM with 92 comments

  • by HippoBaro on 10/5/22, 5:37 AM

    (Context: I write async rust professionally)

    Fly you fools. This will be a nightmare to debug, introspect and reason about for a speed boost that you (and your users) won’t be able to measure.

    If you want to build a native app, more power to you. There are simpler languages that will enable you to do that with a much higher productivity.

    Kudos to the library writer though!

  • by wishawa on 10/5/22, 12:24 AM

    Hi HN! I've been working on Async UI for half a year now, and I think it is time I share it with everyone. The project is not even really usable yet (due to lack of implemented components and documentation), but I think the proof-of-concept is enough to demonstrate this new way of doing UI — a way that, I believe, is more suitable to Rust than existing UI framework designs.

    P.S. My website is new, so if you find any readability or accessibility issue, please let me know!

  • by mbStavola on 10/5/22, 5:39 AM

    I must admit, I was a bit skeptical when reading the title, but after reading I'm super interested.

    The login form example which returns values reminds me a lot of imgui and other immediate mode GUI frameworks.

  • by wruza on 10/5/22, 9:05 AM

    We’re almost back to if (MB_OK == MessageBoxA(…)) and other modal forms, just need to wait a little more for this ui insanity to end and life can be good again.
  • by meltedcapacitor on 10/5/22, 1:38 PM

    Seems a weird mix of async and callbacks spaghetti.

    I´d expect an async UI to be in "immediate UI" style, e.g.:

      async fn give_em_cookies(window:Win) {
        win.title("Cookies!");
        win.columnwise();
        win.label("Which cookie do you like?");
        let cookie = win.selector(&["Shortbread", "Chocolate chip"]).await;
        win.label("When to you want to eat the cookie?");
        win.rowwise();
        if win.button("Now!").await   { eat_cookie_now(cookie); }
        if win.button("Later!").await { eat_coookie_later(cookie); }
        if win.closed().await { no_cookie_eaten(); }
      }
    
      // the function represents the state machine that encodes
      // the behaviour of the dialog box, which the caller gives to UI
      // engine for rendering
      ui.display(give_em_cookies(Window::new())).await;
  • by lucasyvas on 10/5/22, 3:04 AM

    This is wild to me... how does that login_form function work? If awaiting renders, then it can also return values?
  • by royjacobs on 10/5/22, 6:44 AM

    The programming model reminds me of Rob Eisenberg's older attempts at building UI toolkits ([0]). I don't recall if that was fully async or 'just' using a coroutine/generator-style approach, but it feels similar.

    I'm not sure the complexity of doing everything using async constructs is worth it, though. Large-scale UI's built in Qt or Javascript are mostly single threaded anyway, but it's still worthwhile to explore so kudos for that. Looking forward to seeing how far you get.

    [0] https://github.com/Caliburn-Micro/Caliburn.Micro

  • by ohgodplsno on 10/5/22, 2:15 PM

    Today in "HN never used a reactive framework that is not React and is offended when UI is not written with Dear ImGui".

    This is literally the exact style of SwiftUI and Jetpack Compose (down to the author having used the term fragment, I sure hope this isn't leftover trauma from being an Android developer), except written in Rust (hence having to deal with lifetimes in the middle, default parameters, lambdas being quite verbose and needing to move things, etc).

    Not blocking the UI thread is mandatory if you ever want to make any kind of complex UI. If you're a web dev, well you only have one thread anyways, good luck, if you're on any other platform, interactions _cannot_ ever block the UI (unless you, yourself, update the UI to say it is blocked). Making this async is a good thing.

    Stack traces are a problem, but then again they've been a problem in any remotely capable UI toolkit.

    With ReactiveCell, it looks surprisingly similar to what Compose does, where modifying a State<T> causes recomposition of everything observing it. Which means that it might be powerful enough one day to do the same things as Molecule (https://github.com/cashapp/molecule), or ComposePPT (https://github.com/fgiris/composePPT), where everything is a potential target and it interops really well with existing toolkits.

  • by gwbas1c on 10/5/22, 1:25 PM

    Hopefully I can find some time in my busy schedule to try this.

    One thing I like is that the code appears to flow more like a console app than a GUI app. I've always found it's easy to create a quick-and-dirty console app; but if I want to do a quick-and-dirty UI (windows) app, it's much more time consuming.

    This is because, with console IO, you can write your UI in a very linear manner. With UI (windows), it's much harder to write the code in a linear manner.

  • by tayistay on 10/5/22, 4:55 PM

    This is an interesting idea, but if you look at bigger examples, such as the todo-list example, the code is littered with `async` noise, calls to `borrow()`, and other fancy stuff like reducers. (A todo list is easily expressed in SwiftUI without much ceremony) Seems like scaling up to actual apps would be a mess.

    https://github.com/wishawa/async_ui/blob/main/examples/web-t...

  • by cottsak on 10/5/22, 5:02 AM

    sigh

    how did we all survive before async UI... ¬‿¬

  • by cyber_kinetist on 10/5/22, 7:58 AM

    I wonder if one can do this with coroutines in a more ergonomic way. Lua might be a good candidate language to create such a UI framework…
  • by voorwerpjes on 10/5/22, 6:00 AM

    Very cool!

    I don't understand the motivation about lifetimes in sync rust not being able to be arbitrary. I'm also confused because most of the time went you want to send data around in a async context you wrap it in `arc`, which has the pretty much analogous `rc` in a sync context which would also solve the lifetimes issue. Is there something I am missing?

  • by qwerty456127 on 10/5/22, 12:55 PM

    I always dreamt of a GUI library where every widget would be a separate actor sending and receiving messages.
  • by jcelerier on 10/5/22, 2:03 PM

    i'm really curious about the UI performance. a very good way to get lower latency in my usually callback-driven code is to move to synchronous things as far as possible - every callback has a cost, and these costs really add up especially if you want as fast as a startup as is possible for your app. And every step in a coroutine in an event-driven system is pretty close conceptually to a callback, isn't it ?
  • by adamnemecek on 10/5/22, 5:17 AM

    You might be interested in RUI https://github.com/audulus/rui
  • by davidatbu on 10/5/22, 5:17 AM

    So, does this work with an application that uses tokio?
  • by avrionov on 10/5/22, 4:09 AM

    Your scientists were so preoccupied with whether or not they could, they didn't stop to think if they should.
  • by pharmakom on 10/5/22, 6:55 AM

    Looks a bit like concur JS
  • by your_challenger on 10/5/22, 10:37 AM

    This is very Compose (Android) and Swift UI (iOS) like. I love it!
  • by Existenceblinks on 10/5/22, 2:00 PM

    It's 2.56 MB gzip!
  • by cercatrova on 10/5/22, 7:34 AM

    Isn't this basically retained mode vs immediate mode GUIs?
  • by debdut on 10/5/22, 10:01 AM

    has a SwiftUI resemblance, nice :)
  • by fyvhbhn on 10/5/22, 9:08 AM

    Could you compare it with Sycamore with a few bullet points?

    I feel like it is pretty close even though you don't see the async exposed? L

  • by SeniorMars on 10/5/22, 12:48 PM

    I love you wisha <3