TUTORIAL: Why Variables Should Not Be Named Dynamically (eval)

TUTORIAL: Why Variables Should Not Be Named Dynamically (eval)

Stephen23 on 26 Sep 2016 (Edited on 2 Apr 2024)
Latest activity Reply by webdesign on 10 Apr 2024

Summary:
Dynamically accessing variable names can negatively impact the readability of your code and can cause it to run slower by preventing MATLAB from optimizing it as well as it could if you used alternate techniques. The most common alternative is to use simple and efficient indexing.
Explanation:
Sometimes beginners (and some self-taught professors) think it would be a good idea to dynamically create or access variable names, the variables are often named something like these:
  • matrix1, matrix2, matrix3, matrix4, ...
  • test_20kmh, test_50kmh, test_80kmh, ...
  • nameA, nameB, nameC, nameD,...
Good reasons why dynamic variable names should be avoided:
There are much better alternatives to accessing dynamic variable names:
Note that avoiding eval (and assignin, etc.) is not some esoteric MATLAB restriction, it also applies to many other programming languages as well:
MATLAB Documentation:
If you are not interested in reading the answers below then at least read MATLAB's own documentation on this topic Alternatives to the eval Function, which states "A frequent use of the eval function is to create sets of variables such as A1, A2, ..., An, but this approach does not use the array processing power of MATLAB and is not recommended. The preferred method is to store related data in a single array." Data in a single array can be accessed very efficiently using indexing.
Note that all of these problems and disadvantages also apply to functions load (without an output variable), assignin, evalin, and evalc, and the MATLAB documentation explicitly recommends to "Avoid functions such as eval, evalc, evalin, and feval(fname)".
The official MATLAB blogs explain why eval should be avoided, the better alternatives to eval, and clearly recommend against magically creating variables. Using eval comes out at position number one on this list of Top 10 MATLAB Code Practices That Make Me Cry. Experienced MATLAB users recommend avoiding using eval for trivial code, and have written extensively on this topic.
Sign in to participate
webdesign
webdesign on 10 Apr 2024
Thank you, that helped me a lot.
Hassaan
Hassaan on 10 Apr 2024
Very insightful. Thank you.
Ed Wheatcroft
Ed Wheatcroft on 24 Nov 2022
@Stephen23, I just wanted to say thanks for putting this extensive page together. I was about to use eval() for something because I thought there was no other way, but after reading this page from top to bottom I feel like a) I now understand why not to use eval() and b) I know the correct way to solve the issue I was having. I found the 'better alternaives' section especiclaly helpful, as a lot of the other posts about eval() seem to focus heavily on the reasons not to use it, but don't really teach you how to avoid it. Anyway, thanks for creating/maintaining the page :)
Steven Lord
Steven Lord on 30 Apr 2019
Alternative: Use a table or timetable Array
table (introduced in release R2013b) and timetable (introduced in release R2016b) arrays allow you to store data with row and/or column names with which you can access the data. For example, if you create a table with variables named Age, Gender, Height, Weight, and Smoker and rows named with the last names of the patients:
load patients
patients = table(Age,Gender,Height,Weight,Smoker,...
'RowNames',LastName);
you can ask for all the ages of the first five patients:
patients(1:5, 'Age')
or all the data for the patients with last names Smith or Jones:
patients({'Smith', 'Jones'}, :)
You can also add new variables to the table, either by hard-coding the name of the variable:
% Indicate if patients are greater than five and a half feet tall
patients.veryTall = patients.Height > 66
or using variable names stored in char or string variables. The code sample below creates new variables named over40 and under35 in the patients table using different indexing techniques.
newname1 = 'over40';
patients.(newname1) = patients.Age > 40;
newname2 = 'under35';
patients{:, newname2} = patients.Age < 35;
patients(1:10, :) % Show the first ten rows
The code sample below selects either Height or Weight and shows the selected variable for the fifth through tenth patients using dynamic names.
if rand > 0.5
selectedVariable = 'Height';
else
selectedVariable = 'Weight';
end
patients.(selectedVariable)(5:10)
See this documentation page for more information about techniques you can use to access and manipulate data in a table or timetable array. This documentation page contains information about accessing data in a timetable using the time information associated with the rows.
Stephen23
Stephen23 on 30 Apr 2019
Simpler and more robust way to generate a table from that .mat file:
S = load('patients.mat');
T = struct2table(S,'RowNames',S.LastName);
Stephen23
Stephen23 on 17 Apr 2019 (Edited on 2 Apr 2024)
Alternative: save the Fields of a Scalar Structure
The save command has an option for saving the fields of a scalar structure as separate variables in a .mat file. For example, given a scalar structure:
S.A = 1;
S.B = [2,3];
this will save variables A and B in the .mat file:
save('myfile.mat','-struct','S')
This is the inverse function of loading into a structure. Some threads showing how this can be used:
Stephen23
Stephen23 on 30 Nov 2017
PS: eval is Not Faulty:
Some users apparently think that eval (and friends) must be faulty and should be removed from MATLAB altogether. They ask "if eval is so broken, why has it not been removed?"... but it is important to understand that the problem is caused by magically accessing variable names regardless of what tool or operation is used, and that eval (or assignin, or evalin, or load without an output argument, etc.) is simply being used inappropriately because there are much better methods available ( better in the sense faster, neater, simpler, more robust, etc). Read these discussions for good examples of this confusion:
It is important to note that any feature of a language can be used inefficiently or in an inappropriate way, not just eval, and this is not something that can be controlled by the language itself. For example, it is common that someone might solve something with slow loops and without preallocating the output arrays: this does not mean that for loops are "faulty" and need to be removed from MATLAB!
It is up to the programmer to write efficient code.
Stephen23
Stephen23 on 19 Jul 2017
Magically Making Variables Appear in a Workspace is Risky
This leads to many subtle bugs that are extremely difficult to track down, if they are even noticed at all!
1) For a start variables of the same name will be overwritten without warning. Even just a spelling mistake or adding extra variables to a MAT file can change the behavior of your code, and because it depends on the data files that you are working with, can be very difficult to track down.
2) Importing multiple files in a loop can ruin your data: consider what will happen if your code processes a sequence of MAT files, which you think all contain the same variables. But one of them contains different variables (yeah, I know, your data files are perfect... sure). Consider what happens in badly-written, fragile code that simply LOADs directly into the workspace: it will happily process the data from the previously loaded file, without giving you any warning or notification that your data are now from the wrong file. Processing continues using the wrong data.
3) There is another serious yet subtle problem, which is caused by the MATLAB parser finding alternative functions/objects/... and calling those instead of using the magically-created variable: basically if the variable does not exist then the parser does its best to find something that matches where the name is called/used later... and it might just find something! The documentation also explains this:
Some example threads discussing this topic:
Or in some cases the parser might not find anything:
The solution is simple: do not magically "poof" variables into existence: Always load into a structure, and never create variable names dynamically.
Stephen23
Stephen23 on 26 Sep 2016
Alternative: Use more Efficient Ways to Pass Variables between Workspaces (applies to evalin, assignin, etc)
Use nested functions, or pass arguments, or use any of the other efficient ways to pass data between workspaces:
Stephen23
Stephen23 on 26 Sep 2016 (Edited on 2 Apr 2024)
Other Languages: do not use eval!
In case you think that avoiding dynamic variable names is just some "weird MATLAB thing", here is the same discussion for some other programming languages, all advising "DO NOT create dynamic variable names":
Some (most likely interpreted) languages might use, require, or otherwise encourage dynamic variable names: if that is how they work efficiently, then so be it. But what is efficient in one language means nothing about the same approach in other languages... if you wish to use MATLAB efficiently, make your code easier to work with, and write in a way that other MATLAB users will appreciate, then that means learning how to use MATLAB features and tools:
Stephen23
Stephen23 on 26 Sep 2016 (Edited on 2 Apr 2024)
Alternative: load into a Structure, not into the Workspace
The MATLAB documentation explains this in detail:
In almost all cases where data is imported programmatically (i.e. not just playing around in the command window) it is advisable to load data into an output argument (which is a structure if the file is a .mat file):
S = load(...);
The fields of the structure can be accessed directly, e.g:
S.X
S.Y
or by using dynamic fieldnames. Note that this is the inverse of saving the fields of a scalar structure.
It is important to note that (contrary to what some users seem to think) it is actually easier and much more robust to save and load data within a loops when the variable names in the .mat files do not change, as having to process different variable names in each file actually makes saving/loading the file data more complex, inefficient, and fragile.
Summary: when using a loop, keep all variable names the same!
Here are real-world examples of loading into variables:
And finally Steven Lord's comment on load-ing straight into the workspace: