In the past I did a lot of programming with Java, Swift, and other languages where OOP object-graph soup was allowed and easier. I'm re-thinking how to build an app in Rust. Even Arc<Mutex<Thing>>
doesn't really work like a reference to Thing
in those languages, because the mutable lock is not reentrant, so in Rust it seems you need to be aware of what's further up the call stack.
It seems that when I call functions, Rust makes me think more about what those functions need, and pass everything in, with the appropriate ability to mutate, or not, those arguments. I guess this is the way.
An example: I've created a UI widget tree for an app and now one of my root objects (an App
) gets an event from the operating system. It then looks at it's owned UI windows, which own widgets, and chooses a widget to deliver the event to. Now that widget may have an attached event handler that wants to "navigate" the UI to another screen. So that function, executing further down the call stack, needs to reach up to more "root" objects, like a Window
, Screen
, or Navigator
and say something like nav.push( FooScreen(arg1, arg2) )
In the OO languages it would be easier to get that nav
object. Maybe you walk up the tree from self toward the root App
or Window
struct, or maybe you grab a global singleton.
Am I on the right track here that in Rust it's better to pass in that nav
controller, somehow, to the event handlers?
Since it's difficult to include everything that a function might need in parameters, in a couple places I've created a Context
struct that bundles up a few things. So while event handlers in Java might look like void handleClick(Event e)
, in Rust I'm getting something like fn handle_click(e: Event, ctx: &mut EventContext)
.
I don't have a super clear question here. Just looking for comments or general ideas about this, and checking if I'm on the right track.
I feel like Rust needs a "design patterns" book, to replace some of the OOP design pattern books I read years ago.