evalin in caller a command that assigns in caller

8 visualizaciones (últimos 30 días)
Leo Simon
Leo Simon el 18 de Jul. de 2014
Comentada: Matt J el 19 de Jul. de 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 comentario
Matt J
Matt J el 19 de Jul. de 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.

Iniciar sesión para comentar.

Respuestas (3)

Sean de Wolski
Sean de Wolski el 18 de Jul. de 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 comentarios
Leo Simon
Leo Simon el 18 de Jul. de 2014
What about an assignin within an evalin? Same thing?
Sean de Wolski
Sean de Wolski el 18 de Jul. de 2014
Same thing - it would be assigning in the caller which would be the workspace where the evalin was called.

Iniciar sesión para comentar.


Alfonso Nieto-Castanon
Alfonso Nieto-Castanon el 18 de Jul. de 2014
Editada: Alfonso Nieto-Castanon el 18 de Jul. de 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 comentarios
Sean de Wolski
Sean de Wolski el 18 de Jul. de 2014
checkValue will not propagate up the stack. When it is evaluated in evalin, the evalin in checkValue will go down the stack to where the first evalin was called from because that is now the caller.
Alfonso Nieto-Castanon
Alfonso Nieto-Castanon el 18 de Jul. de 2014
Editada: Alfonso Nieto-Castanon el 18 de Jul. de 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...

Iniciar sesión para comentar.


Matt J
Matt J el 18 de Jul. de 2014
Editada: Matt J el 18 de Jul. de 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

Categorías

Más información sobre Debugging and Analysis en Help Center y File Exchange.

Etiquetas

Community Treasure Hunt

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

Start Hunting!

Translated by