How to load many variables form base environment

Dear reader,
Here is a toy example. Inside a user-defined function, I currently use the following syntax:
a = evalin('base', 'a');
b = evalin('base', 'b');
c = evalin('base', 'c');
which allows me to load 3 matlab variables, called a,b,c from base environment into the current function's workspace. In reality I have many more variables, not only 3. Therefore, I am looking for a more elegant way to write this code.
A solution would be to write a new matlab function (I'll call it loadVarsFromBaseEnv.m) which should permit me to call it as follows:
loadVarsFromBaseEnv a b c
However, I have no idea how to write the code of loadVarsFromBaseEnv.m
Any help, suggestion are highly appreciated.

 Accepted Answer

"goal is not to write nice matlab code, but instead structure it in the most convenient way" &nbsp How come you believe there is conflict between "nice" and "convenient"? Whatever these words mean in this context.
Here is an "elegant" code that meets your original requirements. Example of use:
a = 1;
b = magic(3);
c = dir;
JustGetTheWorkDone a b c
prints
Name Size Bytes Class Attributes
a 1x1 8 double
b 3x3 72 double
c 89x1 57407 struct
varargin 1x3 342 cell
where
function JustGetTheWorkDone( varargin )
loadVarsFromBaseEnv( varargin{:} )
whos
end
and
function loadVarsFromBaseEnv( varargin )
try
for jj = 1 : length( varargin )
val = evalin( 'base', varargin{jj} );
assignin( 'caller', varargin{jj}, val )
end
catch
fprintf( 2, 'loadVarsFromBaseEnv: Something went wrong\n' ) %#ok<PRTCAL>
end
end

1 Comment

Thank you very much. This is indeed the code I was looking for.

Sign in to comment.

More Answers (1)

Stephen23
Stephen23 on 7 Apr 2015
Edited: Stephen23 on 7 Apr 2015
"a more elegant way to write this code" would be to pass the variables properly and not make them pop into existence in some workspace like that. The reason that you are finding it difficult is because this is not how passing variables to functions works... that is exactly what function input arguments are for. And indeed, passing arguments is what MATLAB themselves recommend as being best practice:
Note that after the best practice of using the input arguments properly comes using nested functions and then global variables. Have you tried any of these?
The MATLAB Wiki also states that "two related functions, evalin and assignin, can be used to alter variables in different function workspaces. These functions can create bugs which are difficult to reproduce and nearly impossible to eliminate."
For some reason beginners seem to love inventing magical ways of making variables appear and disappear in all sorts of unexpected places, but this is not good programming style and doing this makes tracking the functionality and code debugging extremely difficult. Avoid doing this and learn how to pass variables properly, or use nested functions, etc.. If you want the variables to be more convenient to pass around, put them together in one structure.
The function assignin (just like evalin and eval) is a very powerful tool that short circuit lots of inbuilt code checking and syntax highlighting. It is slower than calling normal code due to JIT having to re-evaluate on every call.
Although many of these pages relate to eval the same comments often apply, so here are some pages explaining why dynamically assigning variable names is a really bad idea in MATLAB:

5 Comments

Stefan's "Answer" moved here because it's a reply/comment to Stephan and not an answer to the originally posted question.
Stephen, I agree with best practice as you state it. However, none of the links you provide solve my problem and for my application they are out of scope.
Here's why. My goal is not to write nice matlab code, but instead structure it in the most convenient way. Imagine I have one file, let's call it parameters.m with declarations of some physical parameters and 1000 other files that need to use these parameters. The question is how can one achieve this?
Option1. Using your suggested best practice, it means that I have to call parameters.m in each of the 1000 files. Now, think that I need to add another parameter inside parameters.m: then I will also have to update all these 1000 files, with the new variable. This is what I want to avoid.
Option2. (what I call the elegant solution) Put all parameters only once in base workspace and then use them directly from there. Apart drawbacks of this alternative, there are also nice advantages, e.g. when working with large lookup tables..
Therefore, I am still looking for a solution to my original problem.
I definitely agree with Stephen on this, as would all other experienced MATLAB programmers, and even you yourself -- evalin() is not the way to go. You asked for better ways (thankfully) because you know evalin() is not "elegant". However your definition of what you call "elegant" in Option 2 is what most experienced programmers would call "hated". The link I always give is the FAQ on how to pass data around to different functions: http://matlab.wikia.com/wiki/FAQ#How_can_I_share_data_between_callback_functions_in_my_GUI.28s.29.3F
Stephen's suggestion (your Option 1) is the way to go. I mean, why do you think calling some utility like parameters.m in a thousand files is worse than calling evalin() or assignin() a bunch of times (once for each parameter) in a thousand files? I just don't get it. That would be worse.
The thing that's got me wondering is why thousand of different m-files all need to get access to the same set of named variables. Well, anyway, when I have some operation that I need my hundreds of different projects to do, I put that code into an m-file and store it in a folder called "Utilities" which is on my path. Then any m-file will be calling the same utility m-file.
Thank you for your reply. The scenario I want to avoid is as follows:
Step1. initially assume parameters.m has 1 variable inside:
function [a] = parameters()
a=1;
Then I copy-paste
[a] = parameters()
into 1000 files.
Step2. then I realize I need to update parameters.m with another variable, so I modify parameters.m
function [a,b] = parameters()
a=1;
b=2;
Then I copy-paste this line of code
[a,b] = parameters()
into 1000 files.
Step3. then again, I realize I need to update parameters.m with another variable
function [a,b,c] = parameters()
a=1;
b=2;
c=3;
Then, again I have to copy-paste this line of code into 1000 files
[a,b,c] = parameters()
Step4. ...
So, what would an elegant solution be in this case?
Thank you.
You can do that, no problem. As you know, if you take only the first return argument from a function, that's fine. Even if the function, or a newer version of it, returns other parameters, you don't have to change your code. The early functions that dealt only with a will be fine -- they don't need to be changed to accept b and c, which they would not even use anyway. And the other m-files which needed b and c, and are the reason you added b and c as return arguments, can accept all 3 return arguments and do whatever they want with them. So there is no reason you will need to change tons of old m-files. The only reason you'd have to do that is if you changed the meaning of what was a, b, and c. For example if the single return argument in early versions was now the middle or last argument in the list, like if you unwisely had function [b,a,c] = parameters(). That would be a bad idea.
@Stefan: a much tidier solution would be to use a structure. So instead of this:
[a,b,c,...] = parameters()
with some unknown number of arguments, you would always simply call this:
X = parameters();
and then refer to the appropriate field in your code:
X.data % or whatever field
this still gives the advantage of individually named (and identifiable) fields, and lets you pass just one variable around. No assignin required!
It is even possible to store this structure in one Mfile that can be designed to add fields on-the-fly, and return selected fields. Something like this:
function out = parameters(field,val)
persistent store
switch nargin
case 0
out = store;
case 1
if isfield(store,field)
out = store.(field);
else
% error or empty output
end
case 2
store.(field) = val
end
end
Which can then be set easily:
>> parameters('data',1)
>> parameters('total',5)
and accessed in the same way:
>> parameters
ans =
data: 1
total: 5
>> parameters('data')
ans =
1

Sign in to comment.

Asked:

on 7 Apr 2015

Edited:

on 8 Apr 2015

Community Treasure Hunt

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

Start Hunting!