I have a code which consists of a single file containing multiple functions, some of which use persistent
variables. In order for it to work correctly, persistent variables must be empty.
There are documented ways to clear persistent variables in a multi-function file, such as:
clear functionName % least destructive
clear functions % more destructive
clear all % most destructive
Unfortunately, I cannot guarantee that the user remembers to clear the persistent
variables before calling the function, so I'm exploring ways to perform the clearing operation at the beginning of the code. To illustrate the problem, consider the following example:
function clearPersistent(methodId)
if ~nargin, methodId = 0; end
switch methodId
case 0
% do nothing
case 1
clear(mfilename);
case 2
eval(sprintf('clear %s', mfilename));
case 3
clear functions;
case 4
clear all;
end
subfunction();
subfunction();
end
function [] = subfunction()
persistent val
if isempty(val)
disp("val is empty");
val = 123;
else
disp("val is not empty");
end
end
When first running this, we get:
>> clearPersistent
val is empty
val is not empty
I would expect that running the function again at this point, with any of the non-0 inputs would result in the val
variable being cleared, but alas - this is not the case. After val
is set, unless we use one of the alternatives shown in the top snippet externally, or modify the .m
file, it remains set.
My question: Is it possible to clear persistent variable in subfunctions from within the body of the main function, and if yes - how?
In other words, I'm looking for some code that I can put in clearPersistent
before calling the subfunctions, such that the output is consistently:
val is empty
val is not empty
Here's a related past question (which doesn't deal with this specific use case): List/view/clear persistent variables in Matlab.
I'm aware of the possibility of rewriting the code to not use persistent
variables at all (e.g. by passing data around, using appdata
, adding a 'clear'
flag to all subfunctions, etc.).
Please note that editing the source code of the function and saving implicitly clears it (along with all persistent variables).
I'm aware that the documentation states that "The clear
function does not clear persistent variables in local or nested functions.
The structure of the actual code is as follows:
Main function (called once)
└ Global optimization solver (called once)
└ Objective function (called an unknown N≫1 times)
└ 1st function that uses persistents
└ 2nd function that uses persistents
As mentioned in the comments, there are several reasons why some variables were made persistent:
One (side?) effect of using persistent variables is making the entire code stateful (with two states: before and after the expensive computations). The original issue stems from the fact that the state was not being correctly reset between invocations of the main function, causing runs to rely on a state created with previous (and thus invalid) configurations.
It is possible to avoid being stateful by computing the one-time values in the main function (which currently only parses user-supplied configurations, calls the solver, and finally stores/displays outputs), then passing them alongside the user configurations into the objective function, which would then pass them on to the subfunctions. This approach solves the state-clearing problem, but hurts encapsulation and increases coupling, which in turn might hurt maintainability.
Unfortunately, the objective function has no flag that says 'init'
etc., so we don't know if it's called for the 1st or the nth time, without keeping track of this ourselves (AKA state).
The ideal solution would have several properties:
clear fname
and clear functions
removes the M-file from memory. The next time you run the function, it is read from disk again, parsed and compiled into bytecode. Thus, you slow down the next execution of the function.
Clearing a function or sub-function from within a function thus does not work. You're running the function, you cannot clear its file from memory.
My solution would be to add an option to subfunction
to clear its persistent variable, like so:
function clearPersistent()
subfunction('clear');
subfunction();
subfunction();
end
function [] = subfunction(option)
persistent val
if nargin>0 && ischar(option) && strcmp(option,'clear')
val = [];
return
end
if isempty(val)
disp("val is empty");
val = 123;
else
disp("val is not empty");
end
end
Of course you could initialize your value when called as subfunction('init')
instead.
A different solution that might work for your usecase is to separate the computation of val
and its use. I would find this easier to read than any of the other solutions, and would be more performant too.
function main()
val = computeval();
subfunction(val);
subfunction(val);
end
Given your edit, you could put the objective function in a separate file (in the private
subdirectory). You will be able to clear
it.
An alternative to persistent variables would be to create a user class with a constructor that computed the expensive state, and another method to compute the objective function. This could also be a classdef
file in the private
subdirectory. I think this is nicer because you won’t need to remember to call clear
.
In both these cases you don’t have a single file containing all the code any more. I think you need to give up on one of those two ideals: either break data encapsulation or split the code across two files (code encapsulation?).