What general choices do I have for passing variables?

What are the general recommended ways to hold data that is passed between processes in Odin?

For example, I would like to follow the SDL3 window width and height and recalculate based on that the changes.

Similarly, if I want to follow mouse coordinates on window.

Rule of thumb, for example in Python, has been to avoid global variables.

1 Like

Tracking data from SDL isn’t really sharing data between processes - you still have one process, I think what you mean is getting the data from a native callback. If you really needed to share data between processes you’d use some IPC.

The first thing I should probably mention is that libraries that take in callbacks can also have a separate pointer parameter that is passed into the callback and you as the user of the library can use this pointer to write the data into a location that is accessible from within and outside the callback. This pointer is typically called something like the “user pointer” or the “context”. If the library provides it, use that.

The second possibility is that the library you’re using is not a native library/bindings, but an Odin library, e.g. core:thread. If it’s written in pure Odin, you can use the built-in context.user_pointer and context.user_index to share data between the callback and its outsides. In my opinion it’s less preferrable to a ctx parameter, mostly because nesting lifetime-bound closures becomes harder with context.user_pointer, since you end up juggling the pointers or doing way too much set up. I don’t remember the exact issue i just remember being unhappy about laytan’s odin-http library.

Otherwise you really have no choice but to use a global variable. I’ve recently relaxed my personal stance on global variables and they can be alright for small scripts or applications that are stateful and do only one specific thing.

Using them for global state is okay, but for bi-directionally passing data between procedures is not okay, so I’d try to avoid it if possible. In your case things like window width and height could very well be a part of your global state, and could theoretically be used anywhere in your application. I’d say it’s a decently healthy application of global variables that is unlikely to cause problems, but may cause confusion if you tie more procedures into using these variables instead of their parameters.

1 Like

I would think this problem as some kind of “messenger” that it would be implicit parametric poly morph, that specializes only on certain types?

I still try to solve this as OOP, when DOP should be the main point.

Sorry, I’m lost, can you clarify your question – what are you trying to do?

Although this isn’t exactly what I was asking about, I think I’m starting to understand. So you are trying to make some structure around SDL events for your application (i.e. you just want to know a good way to read the messages as opposed to just rolling your own message pool)

The second comment I’d like to make is that I don’t really know the rules by which these diagrams works and at least for me these diagrams are unreadable and would probably require some text describing what it means. That said I’ll try to interpret it to the best of my ability.

Judging by the fact that you have layout and Widgets and your Renderer is connected to the Main Loop I presume you are making a retained-mode GUI application, where the events from SDL (user input, window resizes) dictate when the application should be re-rendered. In which case consider this - if the window size changes you need to re-compute the layout of widgets. This means the layout widget doesn’t only need to know the size of the window but also when it changes. If the size of the layout changes it would change the location of other widgets and layouts and those might need to be recomputed as well.

This means what you want to do is – rather than storing the window size, you could actually write your own messaging system with callbacks. Your window would have a “root layout” that would have the size of the entire window. When window resizes, the SDL callback function can call into root layout’s event function telling it “hey you need to resize”, which would resize everything. After root layout finished re-computing everything you can run the renderer.

In pseudocode it’s something like this:

Window :: struct {
  /* ... */
  layout: Layout,
}

Layout :: struct {
   cur_width: int,
   cur_height: int,
   widgets: []Widget,
   // A generic event procedure, would be called with up to two parameters depending on the type
   // of the event.
   event_proc :: #type proc(l: ^Layout, event_type: Event_Type, param1: int, param2: rawptr),
}

Inside your SDL event loop you’d call the event_proc function with parameters window_width and window_height, which would start the process of recomputing the layout for that window size.

tbh this is a hard question because it asks about architecture and you can think infinitely long about this sort of stuff. I’m getting a lil tired so I hope whatever I’ve written above helps

1 Like