7 ms·
Seems like a large part of the complexity is enabling the creation and use of reusable UI components that work in a variety of UI hierarchies and modify a vari
by CyberRabbi 4y ago
Seems like a large part of the complexity is enabling the creation and use of reusable UI components that work in a variety of UI hierarchies and modify a variety of backend models (or app states), in a type-safe way. Is that right or are there other problems attempting to be solved?
The simple way to do this is a callback system. Why is that not appropriate for Rust? Does it require custom ownership dynamics that the borrow checker does not support?
- stormbrew 4y agoBorrow checking gets a lot more complicated with closures that live past their scope. It’s usually much more frustrating than it’s worth.
- tcmart14 4y agoI think I just ran into this issue about a week ago. I started working on a task manager written in Rust using the Cursive library, which provides like an ncurses TUI. Heavy use of callbacks, but all callbacks require a <'static> lifetime. All the structures I make for information on the database of course don't have <'static> lifetimes. I eventually figured out that cursive has a function where you can kind of give it the data, but to pull the data back out requires a lot of cloning and boiler plate code.
- LegionMammal978 4y agoIsn't the standard solution to pass the data within an Rc or Arc? That way, the closure still owns all of its data.
- tcmart14 4y agoI'll need to play around with that. I just started doing a serious dive into Rust about a month ago.
- pornel 4y agoTip for you: when the compiler says you need a 'static lifetime, it's actually trying to say that all temporary references are forbidden and won't work. Arc is a reference, but isn't temporary. Add a mutex or atomic when you need to modify data behind arc. This is the "interior mutability" approach that the article mentions.
- stavros 4y agoThis is very useful, so useful that I can't help but think that the compiler actually should say what you said.
- stormbrew 4y agoI definitely think the error could be improved but I'm not sure it should really say "just shove it in an `Arc<Mutex>`," because that really is only sometimes the right solution and it might lead people to make poor choices by default. I think a lot of the problem is really with the confusingness of the concept of static lifetime in rust to begin with, where it's kinda used for both "lives forever" and "doesn't reference anything that lives longer than it"[1]. I hope someday these meanings get different names, tbh. But when you see that error the naive thought is like... "ok better make it live forever" but it really just means you need to make it something that you control, and there are other ways to do that than a refcounting mutex. [1] https://doc.rust-lang.org/rust-by-example/scope/lifetime/static_lifetime.html https://doc.rust-lang.org/rust-by-example/scope/lifetime/sta...
- viraptor 4y ago
- steveklabnik 4y agoCallbacks are often isopmorphic to a big ball of mutable state, which Rust makes very painful. It’s like the classic Joe Armstrong quite about getting the whole jungle when all you wanted is the banana. You can do it, and if you check out the Gtk/QT bindings you’ll see the boilerplate it introduces. Not insurmountable but many people are interested in figuring out if there’s a better way.
- nicoburns 4y agoI’m sure I’m being naive, but could this be worked around by passing a mutable reference to the state into the callback rather than it closing over the state? Assuming there’s only one UI thread, then only one callback can run at once anyway…
- gpm 4y agoI think the fundamental problem with that approach is that even in single threaded code rust makes it illegal to have to have two pointers where at least one is mutable to the same state. So I can pass in a `&mut State` pointer, but then I can't also pass in a `&mut AnElementInSomeListInState` pointer. Nor can I really have `AnElementInSomeListInState` just have a parent pointer to the rest of the state, because someone has to have a `&mut State` pointer, and they would conflict (also because doubly linked lists are hard in rust).
- GolDDranks 4y agoThe problem is that multiple callbacks might require a reference to the same state, and closing over those references and retaining that callbacks, makes two mutable references to the same state, which Rust makes an illegal pattern. That is indeed safe in single-threaded code, but Rust prevents it nevertheless; there is a famous (in Rust circles) blog post about this: https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/ https://manishearth.github.io/blog/2015/05/17/the-problem-wi... There is a workaround called "internal mutability", an ability to mutate state pointed by a shared pointer. That is syntactically slightly messier, and generally frowned upon. The blog post mentions about this workaround, and also states that it's not ideal so we should strive for better.