Is there a simple way to convert all fields of a struct to local variables?
86 views (last 30 days)
Show older comments
I have a matlab program with a lot of variables (boolean, arrays, doubles, logicals, strings), to the point where it becomes unwieldy to alter the workflow. I often don't know which I'm going to need when I add new functionality.
So if I create a function with a series of recursive function calls and X layers deep I discover I need a variable I didn't feed into it, I need to add those variables in the right order as arguments to every function in the recursion. This seems both risky and tedious. It also makes for messy code as functions get passed 20+ arguments.
So I created a struct "programConstants" at the beginning of the program flow that aggregates all of the variables inside of it. So I can access them like:
programConstants.someThing;
Is there a simple way I can just dump all of the programConstants fields into the scope of a function when I pass it?
I would like to avoid accessing the variables from the struct. For example, if I want "someThing", I'd like to just be able to write:
someThing;
instead of:
programConstants.someThing;
7 Comments
dpb
on 15 Aug 2018
Amplifying on the above, with the structure you don't have to do every function at once; all you must do is begin with the one(s) you're working on actively at the moment and change their interface and add the structure name prefix to the variable(s) being used internal to the function (you did keep those consistent, right?). Everything else can remain as is with the variables existing as separate; you simply have to update the structure as well if it contains results as well as inputs.
This is a less than ideal implementation but will let you make the transition over time rather than requiring a complete refactoring all at once.
But I'd reiterate the others--it'll pay large dividends in the long run if this application has any future life expectancy as sounds as does...
Accepted Answer
Steven Lord
on 15 Aug 2018
I have a matlab program with a lot of variables (boolean, arrays, doubles, logicals, strings), to the point where it becomes unwieldy to alter the workflow. I often don't know which I'm going to need when I add new functionality.
That does sound problematic. The risk of breaking such tightly coupled code is high if you're not very careful.
So if I create a function with a series of recursive function calls and X layers deep I discover I need a variable I didn't feed into it, I need to add those variables in the right order as arguments to every function in the recursion. This seems both risky and tedious. It also makes for messy code as functions get passed 20+ arguments.
I agree with your assessment about the risk, mess, and tediousness.
This isn't directly related to your main question, but one way to reduce some of the risk associated with modifying or refactoring your functions would be to write tests for your functions that can reduce the chance that you'll accidentally change the behavior that some other function depends upon when you update your function. This could also help you if you want to refactor your code to make it easier to understand and extend in the future: extract a small segment of functionality into its own function, unit test it thoroughly, and add an integration or system test for the function(s) that call it.
So I created a struct "programConstants" at the beginning of the program flow that aggregates all of the variables inside of it.
IMO that's a step in the right direction, but you have everything crammed into one struct array. Are there logical groupings of the information that your functions need where you could create multiple struct arrays or perhaps even separate classes? So instead of having programConstants you could have carParameters, personParameters, etc.?
Is there a simple way I can just dump all of the programConstants fields into the scope of a function when I pass it?
There are ways to do what you ask, but I recommend against it. If one of the fields in your programConstants struct matches the name of a MATLAB function (commonly-matched functions include alpha, sum, min, max, etc.) then depending on what you do in your function MATLAB may call the function rather than referring to the variable that was "poofed" like a magician's rabbit into the workspace at run-time.
If you're only going to use a particular piece of data from the struct once in your code, consider just accessing it from the struct. If you know you're going to use a particular piece multiple times, then it may be time to define a local variable. But I would limit this to just what your function is going to use. This would be more work than simply dumping everything from the struct into the workspace, but it would also be less likely to cause the "poofing" confusion I described in the previous paragraph.
4 Comments
Stephen23
on 16 Aug 2018
Edited: Stephen23
on 16 Aug 2018
@Doug Rank: for a project of that size and complexity you need to be using best practice, such as using and following the advice of the static code checking tools to ensure that every function does not have any warnings or obvious bottlenecks. This then requires you to not magically make variables appear in any workspaces, because static code checking tools don't work with variables that magically appear at run time!
Best practice would also include using a good versioning system, e.g. GIT. This will make updating and keeping track of the versions much simpler.
More Answers (1)
OCDER
on 15 Aug 2018
Look into inputParser and the StructExpand option. https://www.mathworks.com/help/matlab/ref/inputparser.html
% S = struct('Var1', 1, 'Var2', 2, 'Var3', 3, 'Var4', 4);
% testFcn(S)
function A = testFcn(varargin)
P = inputParser;
P.StructExpand = true;
P.KeepUnmatched = true;
addParameter(P, 'Var1', 0, @isnumeric);
addParameter(P, 'Var2', 0, @isnumeric);
addParameter(P, 'Var3', 0, @isnumeric);
%addParameter(P, 'Var4', 0, @isnumeric); %This function happens to not need Var4, for example.
parse(P, varargin{:});
P = P.Results;
P %show the output
Or you could just pass the structure itself.
function A = testFcn(S)
if ~isfield(S, 'Var1'); S.Var1 = 1; end
..
0 Comments
See Also
Categories
Find more on Loops and Conditional Statements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!