Why doesn't assignin work in this context?

12 views (last 30 days)
Tom
Tom on 12 Aug 2015
Edited: Walter Roberson on 16 Aug 2015
I have a matlab function which creates a variable named 'duration'.
function doStuff()
duration = 5;
Inside the function I create a uicontrol edit box to allow changing the duration value.
uicontrol(panel, 'Style', 'edit', 'Callback', {@setEditBoxNumber, 'duration', 0, 15});
The callback is a local function.
function setEditBoxNumber(obj, ~, ivar, min, max)
value = str2double(get(obj, 'String'));
if isnan(value)
if ~isempty(ivar)
value = evalin('base', ivar);
end
else
value = clip(value, min, max);
end
set(obj, 'String', num2str(value));
if ~isempty(ivar)
assignin('base', ivar, value);
end
value = evalin('base', 'duration');
value = duration;
end
The last two lines are used for debugging purposes. If duration is set to 4 and I type '2' into the text box the string is properly converted to the number 2. The value returned by the bottom evalin call is 2, but the value of duration is still 4.
This is very confusing. If I type letters in the text box the str2double call returns NaN and the upper evalin call properly retrieves the value for duration. I tried using the caller workspace but there was no change in behavior.
  1 Comment
Tom
Tom on 13 Aug 2015
I mistakenly said that setEditBoxNumber is a local function. It is a nested function, not a local function.

Sign in to comment.

Answers (1)

Walter Roberson
Walter Roberson on 12 Aug 2015
When you use
value = evalin('base', 'duration');
value = duration;
the first line does not change duration in the current workspace, only in the base workspace. The line after that uses the duration of the current workspace, where it has not been changed. Remove the semicolon from the end of the
value = evalin('base', 'duration');
line to see the value as fetched from the base workspace.
  5 Comments
Tom
Tom on 16 Aug 2015
setEditBoxNumber is a nested function inside of doStuff. It is not called directly. It is a callback function called by a uicontrol that is created by function doStuff. It appears that the callback workspace is not the same workspace used when the uicontrol is created.
I am thinking of using a structure which is passed as an argument to the callback. Something like the following:
function setEditBoxNumber(obj, ~, aStruct, fieldName, min, max)
Walter Roberson
Walter Roberson on 16 Aug 2015
Edited: Walter Roberson on 16 Aug 2015
Callbacks are evaluated as if called from the base workspace. If the callback is defined as a nested routine then it can read and write variables in the nesting routine that are assigned values before the nested routine is defined.
function outer
a = 123;
function inner(src, event)
a = 456; %this changes outer's "a"
b = 789; %this changes a local variable "b"
end
b = -11111; %although this belongs to outer, it was not defined before inner() is defined so inner() does not have access to it
set(gcf, 'WindowButtonFcn', @inner)
end
Then the callback of inner() will change outer()'s value of "a", but outer() has already returned so outer() does not get to see the change. If you were to re-execute outer() then because it has the assignment to "a" it would change "a" back to 123. For this reason, functions that nest other functions often end up being "shells" that exist mostly to set something up, with all the real work being done by nested routines whose function handles get stored somewhere.

Sign in to comment.

Categories

Find more on Data Type Conversion in Help Center and File Exchange

Products

Community Treasure Hunt

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

Start Hunting!