2

I have the following function as part of a large codebase, which I inherited:

function = save_function(fpath, a,b,c)
    save(fpath, 'a', 'b', 'c')
end

This function is called at the end of one script, before another script is to be executed. This way, the variable names are properly saved (bad design, I know - I didn't write this code).

Now, I am making changes to the codebase, and realize that I need to store more variables in fpath. I face two options:

  1. Edit save_function to accept more inputs. This would break any other code in the codebase that also uses this function
  2. Write a save_function2(a, b, c, d, e, ...) that I will call in the code that I change. This seems like bad design as well.

What I would ideally like to do, is to allow save_function to take in any number of arguments at a time, and save them all by the variable names that are passed in.

Having done some googling, I found eval and eval_in, which evaluate strings as matlab code. However, there are two problems with using this:

  1. Using eval is horribly slow and quite dangerous
  2. I don't always know the types of my variables beforehand, so I can't create an elegant, generic to_string function

In order to combat the flexible number of variables, I decided to use varargin and inputname as follows:

function = save_function(fpath, varargin)
    names = {}
    for i=1:size(varargin,1)
        names{i} = inputname(i+1);  % have to offset by 1 to account for fpath
    end
    save(fpath, names{:});
end

Unfortunately, since the input variables are held in varargin, they do not exist as their variable names on the stack, so the save line fails

How can I dynamically create these variables on the stack, with their variable names?

1
  • I’m 6 years late, but it seems that you want to call save directly! Commented Apr 15, 2020 at 13:41

2 Answers 2

2

You can use a structure to dynamically define saved variable names.
This option is documented here.

 function save_function( fpath, varargin )     
 for ii = 1:numel( varargin )
     st.( inputname(ii+1) ) = varargin{ii};
 end
 save( fpath, '-struct', 'st' );

As a rule of thumb, structure with dynamic field names is often better than eval or assignin when it comes to dynamic variable names.

PS,
It is best not to use i as variable name in Matlab.

Sign up to request clarification or add additional context in comments.

2 Comments

Changing save_function to save a struct is undesirable, since other parts of the large codebase expect it to save the variables themselves.
@inspectorG4dget read carefully the manual regarding the '-struct' flag in save: it does not save the struct, but save the struct fields as seperate variables, which is exactly what you want.
0

The trick is to use assignin, which takes a workspace, a variable name, and some data. It then creates, in the specified workspace, a variable with the given name, whose value is the data:

assignin(workspace, varname, value)

The workspace identifier can be either 'caller' or 'base'. The former creates the variable in the workspace of the function that called the function within which assignin is called; while the latter... I don't know - it doesn't seem to put the variable anywhere I can see.

The trick is to create a small function to assign variables to the calling workspace, and call this function from within assignin:

function = save_function(fpath, varargin)
    names = {}
    for i=1:size(varargin,1)
        names{i} = inputname(i+1);  % have to offset by 1 to account for fpath
    end
    create_variables(names, varargin);
    save(fpath, names{:});
end

function = create_variables(names, vals)
    for i=1:size(names, 1)
        assignin('caller', names{i}, vals{i});
    end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.