Search code examples
matlabvariablesuser-interfacestaticworkspace

Matlab: Transfer variable from GUI to Base Workspace and new Variables (Static Workspace, Script, Creating new Variables)


I am developing a GUI for an existing script, which expect some Struct Values in the Base Workspace. A GUI shall transfer the User Values to the Base-Workspace and then start the script und close itself immediately. It sounds very simply and the values going with assignin and evalin but i work for days with the Problem that if the script create afterwards values itself, i get the Message:

Attempt to add var_name to a static workspace. See MATLAB Programming, Restrictions on Assigning to Variables for details.

What is the Problem? The GUI is closed and the Script shall use the Base-Workspace without restrictions. How can this be done? The Script is untouchable (not from me) and it expects the variables in the base Workspace, so the GUI should transfer the Values to the Workspace and nothing else. A Static Workspace is not needed. The Workspace shall be free from any restrictions. Shortly: I wish to delete the "Static" in "Static Workspace"


Solution

  • The MATLAB documentation specifies that:

    MATLAB issues an error if you attempt to dynamically add a variable to the workspace of an anonymous function, a nested function, or a function that contains a nested function.

    So, your issue most probably results from calling the script directly from an anonymous callback of some button in your GUI (without details I cannot but guess). If this is the case, then wrap it into yet another function, so you'll isolate the variables created by the script from the anon function workspace.

    Design the wrapper function to accept as arguments the variables that you want to pass to the script, so the script will have what it needs. Also, make sure that you don't nest functions inside your wrapper, because you'll get the same problems.

    Note: contrary to what you'd expect, a script called by a function will not create its variables in the Base workspace, but in the workspace of the function. Only if called from another script it will use the Base workspace for variable creation.

    Example: Suppose the script "his_script.m" requires the variables invar1 and invar2 to be already in its accessible workspace; the output (i.e. the created variables) of the script are the variables outvar3 and outvar4:

    % his_script.m
    outvar3 = invar1 + invar2;
    outvar4 = invar1 - invar2;
    

    Because there's no assignin and evalin we can wrap this into a function my_wrapper.m:

    % my_wrapper.m
    function [outvar3, outvar4] = my_wrapper(invar1, invar2)
            % Pre-create the outputs if the script cannot promise with
            % the hand on the Holy Book of Execution Paths that it will
            % create all the output variables.
            outvar3 = [];
            outvar4 = [];
    
            % Call the script
            his_script;
    end
    

    and the functions arguments will work as inputs for the scripts, the the function's returned values will be the output of the scripts.

    Now you can use your call the wrapper function in anonymous callback of a button, for example:

    % initialization function of your GUI
            % ...
            set(action_button_handle, 'Callback', action_button_callback);
            % ...
    
    % somewhere deep in your GUI code, nested function for
    % manipulating the script
    function action_button_callback(hObject, callbackdata)
        [out1, out2] = my_wrapper(5,3);
        display(out1);
        display(out2);
    end
    
    % ...
    

    I hope the idea is clearer now. Please let me know how it works for you.

    Further comments: One of the main differences between the scripts and functions is that scripts don't have a workspace of their own, while the functions do. The scripts use the workspace of the context that called them.

    This means means that your goal "the GUI should transfer the Values to the Workspace and nothing else" is misleading, because you don't know where's the workspace for the script, unless you call it in the first place.

    If you really want the GUI to write in the Base workspace, you make it do that, but than you should call manually your script from the Console Window, because the context of the Console Window is the Base workspace. Or try to use evalin('base', 'script_name;'); but you need to test (so far I resisted the temptation of using stuff like that - exactly because is so easy to mess up, and I don't want the anathema on me).