Most of my GUI experience is with Cocoa/UIKit (Mac/iOS). ObjC and Swift will let you play fast and loose with concurrent access to state and this is extremely convenient, though leaving the potential for a crash.
A Window might conceptually own a Button1 and Button2. So far this makes sense - if the Window is destroyed, its buttons should also be destroyed. Now imagine we attach an action to Button1 that disables Button2. Perhaps this “action” is a closure. Now we have an independent code block that has a reference to perform a mutating action on Button2. In ObjC you can simply do this by having a pointer to it. Rust won’t have a bar of it unless you use explicitly use reference counting and mutexes. It’s not just UI actions either - scheduled timers, URL downloaders and all kinds of other components need to take ownership of UI at spontaneous times.
Explicit mutexes aren’t the only option - the UI library could abstract over the UI elements so the mutexes are hidden from you - but then you’ve just replaced Rust semantics with Java/ObjC synchronisation so why are you writing Rust? Alternatively you could replace this very convenient event-driven design with a single “processing” function where you temporarily have mutable access to everything - I read about that in the design for one library. I didn’t like the sound of it.
There are options. None of them feels as ergonomic as the dangerous status quo that I’m used to. As I suggested, I’m not yet convinced Rust is a bad choice for this, but any library will have to think carefully to make this not suck. For now I would rather use a battle-tested option.
For Qt and GTK it would be okay if the bindings were high quality and there was good documentation/examples. I am skilled in neither and wouldn’t want the extra hassle of “making it work in Rust” unless this was outweighed by other advantages.
Most of my GUI experience is with Cocoa/UIKit (Mac/iOS). ObjC and Swift will let you play fast and loose with concurrent access to state and this is extremely convenient, though leaving the potential for a crash.
A Window might conceptually own a Button1 and Button2. So far this makes sense - if the Window is destroyed, its buttons should also be destroyed. Now imagine we attach an action to Button1 that disables Button2. Perhaps this “action” is a closure. Now we have an independent code block that has a reference to perform a mutating action on Button2. In ObjC you can simply do this by having a pointer to it. Rust won’t have a bar of it unless you use explicitly use reference counting and mutexes. It’s not just UI actions either - scheduled timers, URL downloaders and all kinds of other components need to take ownership of UI at spontaneous times.
Explicit mutexes aren’t the only option - the UI library could abstract over the UI elements so the mutexes are hidden from you - but then you’ve just replaced Rust semantics with Java/ObjC synchronisation so why are you writing Rust? Alternatively you could replace this very convenient event-driven design with a single “processing” function where you temporarily have mutable access to everything - I read about that in the design for one library. I didn’t like the sound of it.
There are options. None of them feels as ergonomic as the dangerous status quo that I’m used to. As I suggested, I’m not yet convinced Rust is a bad choice for this, but any library will have to think carefully to make this not suck. For now I would rather use a battle-tested option.
For Qt and GTK it would be okay if the bindings were high quality and there was good documentation/examples. I am skilled in neither and wouldn’t want the extra hassle of “making it work in Rust” unless this was outweighed by other advantages.