equivalent of `evalin` that doesn't require an output argument (internally)

心不动则不痛 提交于 2019-12-11 03:10:06

问题


Background -- I was reading up on accessing shadowed functions, and started playing with builtin . I wrote a little function:

function klear(x)
%  go to parent environment...
evalin('base', builtin('clear','x')) ;  
end

This throws the error:

Error using clear
Too many output arguments.

I think this happens because evalin demands an output from whatever it's being fed, but clear is one of the functions which has no return value.
So two questions: am I interpreting this correctly, and if so, is there an alternative function that allows me to execute a function in the parent environment (that doesn't require an output)?

Note: I'm fully aware of the arguments against trying to access shadowed funcs (or rather, to avoid naming functions in a way that overload base funcs, etc). This is primarily a question to help me learn what can and can't be done in MATLAB.

Note 2

My original goal was to write an overload function that would require an input argument, to avoid the malware-ish behavior of clear, which defaults to deleting everything. In Q&D pseudocode,

function clear(x)
if ~exist('x','var') return
execute_in_base_env(builtin(clear(x)))
end

回答1:


There's a couple issues with your clear override:

  • It will always clear in the base workspace regardless of where it's called from.
  • It doesn't support multiple inputs, which is a common use case for clear.

Instead I'd have it check for whether it was called from the base workspace, and special-case that for your check for whether it's clearing everything. If some function is calling plain clear to clear all its variables, that's bad practice, but it's still how that function's logic works, and you don't want to break that. Otherwise it could error, or worse, return incorrect results.

So, something like this:

function clear(varargin)
  stk = dbstack;
  if numel(stk) == 1 && (nargin == 0 || ismember('all', varargin))
    fprintf('clear: balking at clearing all vars in base workspace. Nothing cleared.\n');
    return;
  end

  % Check for quoting problems
  for i = 1:numel(varargin)
    if any(varargin{i} == '''')
      error('You have a quote in one of your args. That''s not valid.');
    end
  end
  % Construct a clear() call that works with evalin()
  arg_strs = strcat('''', varargin, '''');
  arg_strs = [{'''clear'''} arg_strs];
  expr = ['builtin(' strjoin(arg_strs, ', '), ')'];
  % Do it
  evalin('caller', expr);
end

I hope it goes without saying that this is an atrocious hack that I wouldn't recommend in practice. :)




回答2:


What happens in your code:

evalin('base', builtin('clear','x'));

is that builtin is evaluated in the current context, and because it is used as an argument to evalin, it is expected to produce an output. It is exactly the same as:

ans = builtin('clear','x');
evalin('base',ans);

The error message you see occurs in the first of those two lines of code, not in the second. It is not because of evalin, which does support calling statements that don't produce an output argument.

evalin requires a string to evaluate. You need to build this string:

str = 'builtin(''clear'',''x'')';
evalin('base',ans);

(In MATLAB, the quote character is escaped by doubling it.)

You function thus would look like this:

function clear(var)
try
    evalin('base',['builtin(''clear'',''',var,''')'])
catch
    % ignore error
end
end

(Inserting a string into another string this way is rather awkward, one of the many reasons I don't like eval and friends).

It might be better to use evalin('caller',...) in this case, so that when you call the new clear from within a function, it deletes something in the function's workspace, not the base one. I think 'base' should only be used from within a GUI that is expected to control variables in the user's workspace, not from a function that could be called anywhere and is expected (by its name in this case) to do something local.


There are reasons why this might be genuinely useful, but in general you should try to avoid the use of clear just as much as the use of eval and friends. clear slows down program execution. It is much easier (both on the user and on the MATLAB JIT) to assign an empty array to a variable to remove its contents from memory (as suggested by rahnema1 in a comment. Your base workspace would not be cluttered with variables if you used function more: write functions, not scripts!



来源:https://stackoverflow.com/questions/55745035/equivalent-of-evalin-that-doesnt-require-an-output-argument-internally

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!