← Back to context

Comment by josephg

7 days ago

Oh? They tried rust?

Lots of people seem really committed to OOP. Rust is definitely a bad fit if you can't imagine writing code without classes and objects. I don't think this makes rust is a bad language for the problem. Its just, perhaps, makes rust a bad language for some programmers.

It doesn't seem uncommon for someone to generally like Rust but still want to use something OO for UI. I'm in that boat. Never liked OOP much, but it makes sense sometimes.

  • What OO features are you thinking of that Rust doesn't have?

    Traits give you the ability to model typical GUI OO hierarchies, e.g.:

        trait Widget {
            fn layout(&mut self, constraints: Constraints);
            fn paint(&self, ctx: &mut PaintCtx);
            fn handle_event(&mut self, event: Event);
        }
    
        struct Button { ... }
        struct Label { ... }
    
        impl Widget for Button { ... }
        impl Widget for Label { ... }
    
        let mut widgets: Vec<Box<dyn Widget>> = Vec::new();
    

    Implementation inheritance can be achieved with good old shared functions that take trait arguments, like this:

        fn paint_if_visible<W>(widget: &W, ctx: &mut PaintCtx)
        where
            W: HasBounds + HasVisibility,
        {
            if widget.is_visible() {
                ctx.paint_rect(widget.bounds());
            }
        }
    

    You can also define default methods at the trait level.

    This all ends up being much more precise, clear, and strongly typed than the typical OO inheritance model, while still following a similar overall structure.

    You can see real world examples of this kind of thing in the various GUI toolkits for Rust, like Iced, gpui, egui, Dioxus, etc.

    • You can do OO this way if you really want in Rust, kinda like how you can do it in C, but it gets cumbersome. Especially because there's no GC.

      4 replies →

  • Every "OO for UI" approach I've seen breaks most of the rules of object-oriented design.

    GTK, Qt, DOM, WinUI 3, Swing, Jetpack Compose, and GWT (to name a few) all provide getters and setters or public properties for GUI state, violating the encapsulation principle [1]. The TextBox/EditBox/Entry control is the perfect example.

    The impedance mismatch is that a GUI control is not an object [2]. And yet, all of the object-orient GUI examples listed implement their controls as objects. The objects are not being used for the strengths of OO, it's just an implementation detail for a procedural API. The reason these GUIs don't provide an API like shown in [1] is because it's an impractical design.

    "How are you supposed to design an OO TextEdit GUI control if it can't provide a getter/setter for the text that it owns?" Exactly. You're not supposed to. OOP is not the right model for GUIs.

    Ironically, SwiftUI doesn't have this problem because it uses the Elm Architecture [3] like React and iced.

    [1]: https://www.infoworld.com/article/2163972/building-user-inte...

    [2]: From [1], "All the rules in the rule-of-thumb list above essentially say the same thing — that the inner state of an object must be hidden. In fact, the last rule in the list (“All objects must provide their own UI”) really just follows from the others. If access to the inner state of an object is impossible, then the UI, which by necessity must access the state information, must be created by the object whose state is being displayed."

    [3]: https://guide.elm-lang.org/architecture/