The general wisdom about eval()
is: do not use it! At least not until you are really out of reasonable options after consulting more than 3 experts on the newsgroups, forums and support@mathworks.com (if your SMS is current)!
Abusing eval()
turns it into evil()
!
The elves running inside MATLAB needs to be able to track your variables to reason through your code because:
- it helps your code run much faster (
eval()
cannot be pre-compiled) - able to use parallel computing toolbox (it has to know absolutely for sure about any shared writes)
- mlint can warn you about potentially pitfalls through code smell.
- it keeps you sane while debugging!
This is called ‘transparency’: MATLAB has to see what you are doing every step of the way. According to MATLAB’s parallel computing toolbox’s documentation,
Transparency means that all reference to variables must be visible in the text of the code
which I used as a subtitle of this post.
The 3 major built-in functions that breaks transparency are:
eval(), evalc()
: arbitrary code execution resulting in read and write access to its caller workspace.assignin()
: it poofs variables in its caller’s workspace!evalin()
: it breaks open the stack and read the variables in its caller’s workspace!
They should have been replaced by skillful use of dynamic field names, advanced uses of left assignment techniques, and freely passing variables as input arguments (remember MATLAB uses copy-on-write: nothing is copied if you just read it).
There are other frequently used native MATLAB functions (under certain usages) that breaks transparency:
load()
: poof variables from the file to the workspace. The best practice is to load the file as a struct, likeS=load('file.mat');
, which is fully transparent. Organizing variables into structs actually reduces mental clutter (namespace pollution)!save(), who(), whos()
: basically anything that takes variable names as input and act on the requested variable violates transparency because it’s has the effect ofevalin()
. I guess thesave()
function chose to use variable names instead of the actual variables as input because copy-on-write wasn’t available in early days of MATLAB. A example workaround would be:function save_transparent(filename, varargin) VN = arrayfun(@inputname, (2:nargin)', 'UniformOutput', false); if( any( cellfun(@isempty, VN) ) ) error('All variables to save must be named. Cannot be temporaries'); end S = cell2struct(varargin(:), VN, 1); save(filename, '-struct', 'S'); end function save_struct_transparent(filename, S) save(filename, '-struct', 'S'); end
The good practices to avoid non-transparent load/save also reduces namespace pollution. For example, inputname()
peeks into the caller to see what the variable names are, which should not be used lightly. The example above is one of the few uses that I consider justified. I’ve seen novice abusing inputname()
because they were not comfortable with cells and structs yet, making it a total mindfuck to reason through.