Loren on the Art of MATLAB

February 15th, 2006

Nested Function Interaction with Global Variables

Recently on two different occasions, people have asked me to help debug their nested function code. I was struck by the similarity of their problems and today will show you the problem and some solutions.

The problem, simply stated, is this. The users wrote GUIs using nested functions and brought up a single instance which ran fine. Then they brought up a second instance while the first one was running, and ran the second one. So far, so good. Then each user went to the original GUI window and pushed a button. To the surprise of those watching, the action all happened in the second GUI from that moment forward, regardless of which GUI's button was pressed. What was happening?

The users each wrote GUIs using code with this sort of code structure.

function myGUI
 
global hLines hColor
hfig = figure('name','Changing line colors');
hax = axes('parent',hfig);
init();
 
    function init(varargin)
        hLines = plot(hax,magic(3));
        hColor = uicontrol('style','pushbutton',...
            'string', 'Change line colors', ...
            'units','normalized',...
            'position',[0.01 0.01 0.25 0.05],...
            'callback',@changeColor);
    end
 
    function changeColor(varargin)
        colors = {rand(1,3); rand(1,3); rand(1,3)};
        set(hLines, {'Color'}, colors);
    end
end

Notice that some of the handles are declared to be global. Both the init and myStop functions need access to this information, but the main function myGUI doesn't know about them. However, declaring them global (persistent would have the same effect here since there's only one file) is what's causing the first and second instances to both point to the line and uicontrol handles in the second figure, causing incorrect interactions.

How can you stop that from happening? Two ways:
  1. Instead of declaring the shared variables global, simply initialize them. Replace:
    global hLines hColor
    
    with
    hLines = []; hColor = [];
    
  2. Here's a solution that is perhaps even more elegant. Since init only gets called once, don't make it a nested function and instead include the code directly in myGUI. Since that code runs when myGUI is created, the variables in question are automatically initialized to their correct values and are now visible to the changeColor nested function. The code is now slightly shorter, possibly even more readable, and doesn't have unpleasant side effects.
function myGUIclean
 
% initialize GUI
hfig = figure('name','Changing line colors');
hax = axes('parent',hfig);
hLines = plot(hax,magic(3));
hColor = uicontrol('style','pushbutton','units','normalized',...
    'position',[0.01 0.01 0.25 0.05],'string','Change line colors',...
    'callback',@changeColor);
 
% callback for pushbutton
    function changeColor(varargin)
        colors = {rand(1,3); rand(1,3); rand(1,3)};
        set(hLines, {'Color'}, colors);
    end
end

For a more complex GUI example, see The MathWorks News & Notes - January 2006 article and find the code on the MATLAB File Exchange.

7 Responses to “Nested Function Interaction with Global Variables”

  1. DavidB replied on :

    Hi, I think your example with nested are nice and i cant do the same.
    I am running Matlab6 but no way to share variable efficiently
    -for exemple I run the nested function ‘taxdemo’
    taxDemo(30) %%Matlab example
    ” ??? Undefined function or variable ‘AdjustedIncome’.”

    Furthermore, when I am inside a function into i cannot access global variables defined in the main workspace, with the exception of nested global variables, for exemple somthing like that:
    function param=opt(goal)
    global G
    G=goal;
    …..
    param = lsqnonlin(@circuit,Z0,LB,HB,cond);
    function F = circuit(Z)
    %acces global
    end
    end

  2. Loren replied on :

    Nested functions are a new feature in MATLAB 7 which is why the code didn’t work in MATLAB 6 when you tried it there.

    I recommend you read the documentation on using global variables to understand how to access them. In each workspace that you want to see a particular global variable, you must declare that before making reference to it. This includes functions and the base workspace.

  3. Rehan replied on :

    Hi
    I have built my code in MATLAB 7. I have a problem. I used global variables in the function for example img_global. Now by using imread, I get the input image and using imshow create an instance showing image. Later in the function, I create another using figure(’Name’, ‘Label’) alongwith the msgbox of the result. msgbox and seconf figure is there but first figure disappears. Please help

  4. Dmitry Vedenov replied on :

    Loren:

    I have a somewhat different problem with nested function, I am not sure what the solution could be. I have about six structurally identical nested functions within a wrapper function that takes as an in input a string with a name of the nested function to call, for example

    function u = WrapperFun(u,funname)

    function u = A()

    end %A
    function u = B()

    end %B

    end %WrapperFun

    where funname can be ‘A’ or ‘B’. I thought I can use feval(funname) to call the nested functions, but I am getting an error suggesting that feval cannot see the nested functions. Is there a different way to do this?

    Thank you

  5. Loren replied on :

    Dmitry-

    You might want to rearchitect your code so WrapperFun returns handles to the nested functions, perhaps in a struct or a cell array. Then use those handles.

    –Loren

  6. Vaclav replied on :

    Loren:

    Based on the discussions on nested functions on the Mathworks Blogs, I have rewritten my code to be ‘nested’ so as to avoid ‘Out of Memory’ problems when repeatedly passing large arrays to sub-functions.

    These sub-functions were originally used by different parent functions, hence it would be convenient to maintain a single source code for them.

    Do I achieve a similar benefit in terms of memory efficiency (avoid replication of memory space for large variables), if the nested sub-functions use “feval” to execute a code in a separate .m file? Is there any other solution ? (i am not sure i understand the matlab implementation of nesting properly).

    Thanks

    Vaclav

  7. Loren replied on :

    Vaclav-

    You still get the memory savings applying the nested function outside the file. But you do not need to use feval. Simply pass the function handle, let’s say fh, and evaluate it in your other program: fh(arg1,arg2).

    –Loren

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Jun: I totally can not believe it, Loren. You are really helpful. Thank you so much, MATLAB master!
  • Loren: Wow folks- Always lots of interest when there’s a quickie to try out! I will only make 2 general...
  • Loren: Jun- ismember is your friend here: >> [aa,ind] = ismember(Array2,Arra y1) aa = 1 1 1 1 1 1 1 ind = 1 2 1 4 4 3...
  • Dan: I like the first way better than the second way. Combining the arrays into one and running any is nice, although...
  • James Myatt: How about I = (a == 0 | b == 0); a(I) = []; b(I) = [];
  • Tunc: Hello Loren, love your blog because of such inspiring and challenging comments to such ’small’...
  • Pekka Kumpulainen: Here is my tradeoff. I usually want to keep the original variables as they are most probably...
  • Iain: Followup: Of course, to allow NaNs (counting them as non-zero): mask = (a~=0) & (b~=0); The mask says “a...
  • Matt Fig: I would usually go with something like this: y = a&b; x = a(y); y = b(y); But I was surprised to find...
  • kk: c=all([a;b]) a(c) a(b)

These postings are the author's and don't necessarily represent the opinions of The MathWorks.