evalin in caller a command that assigns in caller

11 views (last 30 days)
Leo Simon
Leo Simon on 18 Jul 2014
Commented: Matt J on 19 Jul 2014
Matlab documents that nested evalin's don't work. They don't appear to document that an assignins within evalins don't work. In fact these seem to be recommended in various places, as a workaround. But these don't work either, as the following example illustrates.
function nothing
firstLevel
pause(2)%This is just to show that it's not a matter of not waiting long enough
n
function firstLevel;
secondLevel
function secondLevel
evalin('caller','assignin(''caller'',''n'',1)')
Threads which discuss this issue, e.g.,
https://www.mathworks.com/matlabcentral/newsreader/view_thread/270127
are littered with lectures about what bad programming practice it is do to this sort of thing. These seem a little patronizing to me.
Isn't it a little presumptuous to evaluate all programming practices in one sweep and conclude that they are all really bad.
For example, I like to evalin('caller','VARIABLE'), but want to be sure that I've a value to VARIABLE in caller before I do so, etc. It's a royal pain to have to repeatedly check the existence of VARIABLE in caller, etc., every time I want to do this. (Obivously I could do a try, catch but EVERYBODY agrees that THESE are bad programming practice.) So a natural thing to do is to delegate this precheck, along with other handy things, to a function that does all the repetitive work for me, but needs programming just once. But that requires a nested evalin, which matlab has declared to be bad programming practice and thus prohibited it, even though it's functionally 100% equivalent to a regular evalin.
I can workaround the prohibition on nested evalins if my example above worked. But as n oted it doesn't.
  1 Comment
Matt J
Matt J on 19 Jul 2014
Isn't it a little presumptuous to evaluate all programming practices in one sweep and conclude that they are all really bad.
The thread you've referenced doesn't talk about all uses of evalin, however. It talks specifically about using it (and its cousins eval, assignin, load, etc...) to insert variables into a workspace and modify them non-explicitly. Several dangers of doing so were cited in the thread. Explanations were also given about why you normally shouldn't have to do this. But nobody there claimed or would claim that these recommendations cover all possible scenarios.
But that requires a nested evalin, which matlab has declared to be bad programming practice and thus prohibited it, even though it's functionally 100% equivalent to a regular evalin.
Just for the record, it's not just nested evalins that are considered bad practice. Use of even a single evalin to create variables are also discouraged.

Sign in to comment.

Answers (3)

Sean de Wolski
Sean de Wolski on 18 Jul 2014
Nested evalins don't work not because it's a bad programming practice but because the caller of the nested evalin is the original caller (i.e. the bottommost function).
Use try/catch and regular function outputs as necessary to pass variables back up the stack.
  2 Comments
Sean de Wolski
Sean de Wolski on 18 Jul 2014
Same thing - it would be assigning in the caller which would be the workspace where the evalin was called.

Sign in to comment.


Alfonso Nieto-Castanon
Alfonso Nieto-Castanon on 18 Jul 2014
Edited: Alfonso Nieto-Castanon on 18 Jul 2014
There is no viable work-around for nested evalins, but your particular example does not really require them. You could for example define all your check-ups in a function like:
function val = checkValue(var)
if evalin('caller', sprintf('exist(''%s'',''var'')', var))
val = evalin('caller', var);
else
val = 'variable does not exist';
end
end
and then simply use the syntax
evalin('caller','checkValue(''n'')');
to get the value of n from the caller workspace (or an error string if n does not exist there). Would that work for you?
  2 Comments
Alfonso Nieto-Castanon
Alfonso Nieto-Castanon on 18 Jul 2014
this is not intended to propagate up the stack (not possible). This is intended to encapsulate the checks (e.g. to make sure the variable exists in the caller workspace) into a single function.
The second evalin will be evaluated in its caller space, which is the same space as the original call caller space. In other words:
function test01
n = 2;
test02;
end
function test02
value = evalin('caller','checkValue(''n'')');
disp(value);
value = evalin('caller','checkValue(''m'')');
disp(value);
end
>> test01;
2
variable does not exist
>>
The trick here is that checkValue is not called from test02 but from test01, and that both checkValue caller and test02 caller spaces are the same. This should allow you to encapsulate all of your checks inside checkValue without having to repeat them for every call to evalin. Does this make sense?
Just to clarify, this addresses the following point in the original poster question:
For example, I like to evalin('caller','VARIABLE'), but want to be sure that I've a value to VARIABLE in caller before I do so, etc. It's a royal pain to have to repeatedly check the existence of VARIABLE in caller, etc., every time I want to do this ... So a natural thing to do is to delegate this precheck, along with other handy things, to a function that does all the repetitive work for me, but needs programming just once. But that requires a nested evalin...

Sign in to comment.


Matt J
Matt J on 18 Jul 2014
Edited: Matt J on 18 Jul 2014
Maybe the following is what you're looking for? If so, note that you don't have to go up 2 levels in the stack. You can do it all from just one level down.
function provide(varname,val)
%Check if variable exists. If not, create it with a desired value.
%
% provide(varname,val)
%
%If the variable named VARNAME (a string) does not already exist in
%the current workspace, it will be created and set to VAL.
varexists=evalin('caller', ['exist(''',varname,''',''var'');']);
if ~varexists,
assignin('caller',varname,val);
end

Community Treasure Hunt

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

Start Hunting!

Translated by