Global struct or separate globals for callback optimization?

3 visualizaciones (últimos 30 días)
Jordan
Jordan el 9 de Jul. de 2024
Comentada: Steven Lord el 10 de Jul. de 2024
If I needed a collection globals to store actively updated information, would it be better (run faster, run more efficiently, have less possibilities for bugs) to have a global struct in place of multiple globals? The various callbacks that update the information don't use every single global, so a struct would bring along extra information in many of the places it is needed.
The motivation for this question is the UI I have designed, as globals are the only way that I currently understand how to enable interrupting callbacks to change the value of a variable that must be recognized by the interrupted callback. There is likely a better way to do this that doesn't use globals, but my browsing didn't reveal anything simple enough for my skill level and deadline. (please link alternatives to globals)!
Example:
%lines stores line graphics objects with 2 axes of 3-dimensional data
%each row in this array is an increment of the 3rd dimension
global lines; %is global for interrupting property changes of lines
lines = gobjects(80,4); %80 lines for each of 4 data sets
%Whether or not a playback iterating through each row of lines stops itself
global pauseState;
pauseState = true;
Where they would be replaced by the struct
global s;
s = struct('paused',true,'lines',gobjects(80,4))
s = struct with fields:
paused: 1 lines: [80x4 GraphicsPlaceholder]
Used by the callback functions
function pause()
global pauseState; %Here only one global is used, struct would be wasteful?
pauseState = true;
end
%While play() is running, pause() is called, interrupting and breaking the loop
function play()
global pauseState; %Here both globals are used, struct would be more compact
%global delay; %Another possible global
global lines;
%global lines2;
pauseState = false;
for i=1:1:height(lines)
if pauseState == true
break;
end
%do stuff
%[lines(i,:).Visibility] = deal('on'); %or something
%drawnow;
%pause(delay); %Dictate pacing of play loop
end
end
For the sake of simplicity, the operative code within play() is omitted since there would need to be more than placeholder graphics objects.
This example is not too far off from what a portion of my UI actually does, so these are some of the circumstances in which the struct substitution would be employed. I'm not sure of other cases.
The globals used here are of drastically different sizes, which I mention since the answer to this question may depend greatly on the size of the globals that would be replaced by the struct. Not all of the globals I am using are so polarized in size, like how "delay" and "pauseState" are a double and a logical value (both small).
Thank you!
Notes: I do not have any run errors or warnings, and I have not run into any issues with using multiple globals. I also use the clear; command at the top of my file which may be why I haven't run into any issues with globals. The two callback functions here are used with uibutton objects.
  2 comentarios
Stephen23
Stephen23 el 9 de Jul. de 2024
Editada: Stephen23 el 10 de Jul. de 2024
Use nested functions:
" I also use the clear; command at the top of my file..."
Best avoided. Better: use functions/classes to achieve a known workspace state.
Jordan
Jordan el 10 de Jul. de 2024
Editada: Jordan el 10 de Jul. de 2024
Thank you Stephen23 for the comment, I had seen nested callbacks recommended before but at the time I didn't understand how they would help, since I didn't think of "main function" broadly enough. second link: "nested callback functions share a workspace with the main function. As a result, the nested functions have access to all the UI components and variables defined in the main function." Aka, wrap the necessary data in a function and nest callback functions inside that function.

Iniciar sesión para comentar.

Respuesta aceptada

Rik
Rik el 10 de Jul. de 2024
Editada: Rik el 10 de Jul. de 2024
You should only be using global variables when you have no other option, and you almost always have.
In the context of a GUI, you can use guidata to store your variable s. This achieves the same result, without the debugging nightmare that a real global will cause. For a GUI based on uifigure or AppDesigner you can use properties.
Remember that if you use s as a global variable, no other function in your entire codebase can use that name for a global variable anymore. If you use code written by somebody else, you will get errors which are incredibly hard to debug.
If you have no other option (so you can't use nested function, can't use a class, can't use guidata), then at the very least you should make sure to use as many of the 63 characters you're allowed in a variable name. Make it as descriptive as you can to avoid name collisions. (I vaguely recall reading the limit might be increased a future release. If so, you can use namelengthmax to find the value for your release.)
And finally, to answer your question: there is no penalty to using a struct, since a global variable is already in memory and you're just accessing it as normal.
  3 comentarios
Rik
Rik el 10 de Jul. de 2024
I'm not entirely sure I follow what you're saying.
With guidata it is best practice to store a struct with the main figure of a GUI. If you supply an object instead of a figure, it will find the parent figure. Once the struct is there, you can use it as you would any struct.
I don't think I would recommend using addprop; I would initialize your AppDesigner app (or class) with those fields from the start. That would also avoid warnings/errors when trying to add properties that already exist dynamically.
But I'm glad to be of help.
Steven Lord
Steven Lord el 10 de Jul. de 2024
Remember that if you use s as a global variable, no other function in your entire codebase can use that name for a global variable anymore. If you use code written by somebody else, you will get errors which are incredibly hard to debug.
@Rik, it's a little worse than your first sentence suggests, though your second sentence is (if you're lucky!) correct.
If your code uses s as a global variable, then any other function that includes the statement "global s" (or "global q r s" etc., so searching for "global s" may not find the line in that other function that makes s global) gets access to that same s global variable and can affect how your code works. It's not like each function has its own global workspace or can say "only code that I approve of can access the global variable s."
If you're lucky, that other code will make a change to the global variable s that is incompatible with how your code uses the global variable s and so cause your code to error. If you're not lucky, it will make a change to s that still allows your code to run but makes your code return the wrong answer silently, with no indication that there's a problem. So you may not even realize you have something to debug, and when you do realize it actually doing the debugging (as you point out) could be difficult and/or time consuming.
Also FYI, "I vaguely recall reading the limit might be increased a future release." -- that's correct. See the Release Notes.

Iniciar sesión para comentar.

Más respuestas (0)

Categorías

Más información sobre Migrate GUIDE Apps en Help Center y File Exchange.

Productos


Versión

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by