I'm working on a library in which I have a bunch of Widget
types (Label, Button, Switch, VStack, List, etc), and I'm currently storing Widgets
in SlotMaps, keyed by WidgetId
. My widget slot-maps are currently part of root Window
, so I can find a widget with a Window
+WidgetId
pair, which in other languages might be just a Widget
object pointer.
My question is, should I pass the Window
around everywhere, or should I move my widget slot-maps to a static mut
container, so that I only pass around WidgetIds
? I thought static muts
where "bad", but passing around the Window
also seems awkward. Maybe it's just that I need to get used to it, because it's different from other languages.
[edit to clarify: widgets vs widget types]
static mut
is bad. If you decide to have global state, use OnceLock (or LazyLock
), with a Mutex
or RwLock
if needed. Those were added to std
in large part because even experts tend to create UB with static mut
.
Another alternative to passing around is to use Arc<Mutex<_>>
or Rc<RefCell<_>>
so that everything that needs to query Window
shares ownership of the Window
.
Another pseudo-alternative to passing around is to implement things on "view types" that hold a reference to Window
(so you call methods on the view type instead of explicitly passing a reference to Window
). Though it can sometimes lead to borrow checker headaches.
2 Likes
You're talking about two different kinds of look-ups.
Storing the widget type in a static, read-only map seems like a good idea, assuming there is a fixed number of them and you can create them up front.
Finding the widget requires the window, so you have to pass the window, right? And storing the window in a global probably doesn't make sense. Or do I misunderstand?
Let me edit my question - sorry. I'm storing the widgets in the window, not the types. I mean I have lots of types of widgets, like Labels, Buttons, VStacks, Checkboxs, etc.
Then using a static map doesn't make sense to me. These are objects that can come and go, so they don't necessarily exist for the entire lifetime of the program.
I guess I'm also not entirely sold on this object-ID and slot-map design. I've been working with it but haven't seen much benefit yet. My experience for other languages makes me want to just have "objects", so Rc<RefCell<dyn Widget>>
.
Yeah, the Widgets
come and go, though maybe not quickly, as they represent a UI on screen. The owner/container/slot-map though could be there for the entire program.