Nine Ways to Do Inheritance in Rust, a Language Without Inheritance
medium.com
medium.com
However, the only time where I’m missing code/data reuse through inheritance is with GUI. Some mostly flat hierarchies of widgets are really powerful ways to declare and compose UI components with shared behaviors.
In rust, the DX for GUI components is always lacking compared to web, C#. With maybe the exception of Slint which is really not Rust anymore.
Is there a way to have good DX for GUI components in Rust?
But essentially it comes down to traits, newtypes/enum variants, and macros.
But it’s still really fresh, they are conscious of the issues and I hope bevy maintainers came up with an elegant design
Yes. Rust is not a general purpose language. It's a systems language. Don't use it for GUIs and games and such until somebody has figured out how to do it properly.
Usually when people say to prefer composition over inheritance, that does not apply to the inheritance found in GUI, but as an alternative way to share behaviors as a property, « has a » instead of « is a », like has a role instead of being a user, admin..
That do not work well with GUI, where hundreds of of components are reusing common containers, widget behavior, it would be very verbose and painful to always declare common behaviors, data.
I think, React is cheating because it’s based on the web which already provide DOM node components and JavaScript, a GC language where most rust issues do not apply, there is already an underlying composition framework, the problem is that it is not easy to reproduce in rust.
See VB 5 and 6 (when VBX got replaced by COM), and anything WinRT, UWP, WinUI.
The work Microsoft has been doing on windows-rs translates quite good into Rust, unfortunately the team doesn't like using designers.
To do this in Rust, the closure needs a mutable reference to the button. However, the GUI event loop also needs a reference to the button to draw it on the screen. In Rust, you can have many immutable references, __or__ exactly one mutable reference, but never both at the same time. Since the GUI framework holds the button, it won't let your closure mutably borrow it at the same time.
use std::rc::Rc;
use std::cell::RefCell;
struct Button {
text: String,
on_click: Option<Rc<dyn Fn()>>,
}
impl Button {
fn new(text: &str) -> Self {
Button { text: text.to_string(), on_click: None }
}
fn draw(&self) { println!("[Button: \"{}\"]", self.text); }
fn fire_click(button: &Rc<RefCell<Button>>) {
let cb = button.borrow().on_click.clone();
if let Some(cb) = cb {
cb();
}
}
}
fn main() {
let button = Rc::new(RefCell::new(Button::new("Click me")));
let cb_handle = Rc::clone(&button);
button.borrow_mut().on_click = Some(Rc::new(move || {
cb_handle.borrow_mut().text = "Clicked!".to_string();
}));
button.borrow().draw();
Button::fire_click(&button);
button.borrow().draw();
}
Prints: [Button: "Click me"]
[Button: "Clicked!"]Many interactive programs can be GetInput(); ChangeState(); DrawState();
Why wouldn't their lifetimes be isolated?
Also the drawing doesn't need a mutable reference.
For a long time the most important thing missing was a better story around upcasting, but Rust 1.86 implemented the usual child-to-parent upcasting [0] expected in OO (with the Any trait doing the parent-to-child downcasting [1] in a way that's less error prone than most OO languages actually)
Also note that Firefox and Servo were a early proponents of getting more OO into Rust (I guess that's because they need to deal with the DOM? Not sure). Which doesn't mean literally having classes and inheritance, but rather, language features that can emulate those when needed.
Today I think the missing piece is fields in traits: a way for a vtable to store field offsets rather than just pointers to method; current practice is to add getters and setters to traits when needed (but that's "ugly"). Unfortunately discussion around this stalled [2]
[0]: https://blog.rust-lang.org/2025/04/03/Rust-1.86.0/#trait-upc...
[1]: https://doc.rust-lang.org/std/any/index.html
[2]: maybe the latest one is https://internals.rust-lang.org/t/fields-in-traits/6933/ but idk
I've been wanting for a long time to re-implement Perl's Moo/Moose/Dios in Rust via macros. I think that would make for some really nice (but non-rust -looking) ways of doing all sorts of object hierarchy stuff
Rust traits can't have associated data. That's the big difference from objects.
It's also hard to have a parent-child relationship where the child can find the parent. That takes much fooling around with wordy combos of Rc, Weak, upgrade, etc.
This makes it hard to convert C++ programs, and C++ programmers, to Rust. It's quite possible to write 100% safe code under Rust's constraints, but it takes a major rethink from C++.