I'm trying to run some MATLAB code that is structured as a collection of functions that call other functions, with varying depths of call stack (some of these functions are defined in a single .m file, many are in separate .m files - as far as I gather, MATLAB uses the term "nested" only to describe functions declared within the body of another function, of which these are not).
Some of the low-lying functions require various parameters, that were until recently hardcoded to specific values. I'd now like to be able to change them.
Although ugly, this works (for non-parfor execution) using global variables and the following function:
function [value] = getValueOrDefault(varName, defaultVal)
eval(strjoin(["global", varName]));
if exist(varName, 'var') && ~isempty(eval(varName))
and can be used by declaring at the entrypoint a list of global variables
global myVarName; myVarName = true;
then setting them (then updating calling code to use
myVar = getValueOrDefault('myVarName', false);
or similar.
However, whilst I can run this if the bulk of the code runs inside a parfor loop, the variables are always empty (that is, as I understand, they are created by the getValueOrDefault call, and the original calls are not passed through to the parfor workers). The defaults are always used, which doesn't solve my problem.
Attempting to use something like
global myVarOuter; myVarOuter = true;
parfor n=1:5
global myVar; myVar = myVarOuter;
doStuffThatCallsStuffThatEventuallyWantsMyVar();
end
hits errors in the declaration of global variables within parfor workers.
I don't need the variables to be linked between workers, and I don't need to be able to change them in the workers. I don't care to recover them after the loop finishes.
I tried looking at parallel.pool.constant values, but it wasn't clear to me how I might reference such a constant from an arbitrarily far-away function (that is, I don't think I can make it global in any fashion, and I'm not sure if I can make it persistent - but then I'd need to be able to make the function or class wrapping the persistent variable/struct of options global).
evalin also seems unsupported, at least in thread-based pools (would this be a workaround for processes?)
Passing the variables through the many layers of functions is of course possible, but I'd prefer to avoid it (particularly if I imagine something like the code below)
function myFunctionWithTwoTypesOfExecution(typeVar)
switch type
case "version1"
varForVersion1 = getValueOrDefault('paramForOne', 12345);
doStuffType1(varForVersion1);
case "version2"
varForVersion2a = getValueOrDefault('paramForTwo_first', 123);
varForVersion2b = getValueOrDefault('paramForTwo_second', false);
doStuffType2(varForVersion2a, varForVersion2b);
end
end
Is there a construct/mechanism that will help me with this problem? (Something like React's 'Context' comes to mind - in that case, the goal is to avoid a 'problem' they name "prop drilling", basically identical to modifying all of my functions to pass either an options struct with options for every possible function they might call, or passing a very long list of arguments to each function, which would in my opinion be really awful).
Can 2025a's workspace passing mechanisms solve this issue? (I can't get access to 2025a for our cluster, but it would at least give a route forwards when 2025b releases).