I have made a routine called EXPLODE which works basically like the
PHP function EXTRACT (this one is more violent *hehe*). It works in
the same way: It import variables into the current workspace from a
struct.
(Please have a look at explode.m [attached below] before continuing)
The routine is supposed to work like this:
>> foo.x=1;
>> foo.debug=1;
>> explode(foo)
>> which x
x is a variable.
>> x
x =
1
>> which debug
debug is a variable.
>> debug
debug =
1
>>
The problem is that assignin('caller','debug',1); does not work from
all caller environments. Maybe because 'debug' is a restricted
variable name. (debug.m is found in PATH).
As we saw, the explode routine works when I call it from the base
workspace, but not when I use it from a subroutine, like
test_explode.
(And now, please have a look at test_explode.m)
I run the test_explode function and I get this:
>> test_explode
foo =
x: 1
foo =
x: 1
debug: 1
x is a variable.
debug is a variable.
x=1
??? Attempt to execute SCRIPT debug as a function:
/pkg/matlab/r2008b/toolbox/matlab/codetools/debug.m
Error in ==> test_explode at 8
disp(['debug=' num2str(debug)])
>>
Can anyone help me solve this "non-problem"? I want to at least *be
able to* use debug as a variable name in he sense I showed above. And
I definitely do not want Matlab to lie to me (the result of "which"
is wrong.)
Thank you!
/Henrik Holst, Sweden
explode.m
=========
function explode(varargin)
%EXPLODE Expand a struct in the caller workspace
% EXPLODE(STRUCT,...)
%
% foreach FIELD in STRUCT
% assign variable FIELD in caller workspace the value from STRUCT.FIELD
% end
%
% If multiple STRUCTs are are passed, they are expanded sequentally.
for n = 1:nargin
struct = varargin{n};
if ~isstruct(struct)
error(['argument ' num2str(k) ' is not a structure'])
end
names = fieldnames(struct);
for k = 1:length(names)
name = names{k};
evalin('caller',[name,'=[];']); % not needed?
assignin('caller',name,getfield(struct,name));
end
end
test_explode.m
==============
function test_explode
foo.x = 1
foo.debug = 1
explode(foo)
which x
which debug
disp(['x=' num2str(x)])
disp(['debug=' num2str(debug)])
--
Henrik Holst, Sweden | TYPING IS NO SUBSTITUTE FOR THINKING
holst CHR(64) nada.kth.se | - A Manual for BASIC,
http://www.nada.kth.se/~holst/ | Darthmouth College, 1 October 1964
Sorry, I don't think you can. It's a known hazard of assignin(), evalin(), etc...
MATLAB has no way of detecting whether variables created using these functions conflict with names of existing scripts/functions
The best you can do is modify explode.m to warn you of such a conflict, as in my very similar function below
function unpackstruct(S)
%Takes the fields of the structure S and makes them individual variables
%in the current workspace.
%
%Usage: unpackstruct(S)
%
% !!!!!!!!WARNING!!!!!!!
%
% unpackstruct() will not gracefully create variables when the variable
% name is already in use as a function visible to MATLAB. The "whos"
% command will recognize it as a variable name, but it will still execute
% within the workspace as the pre-existing function.
%
% This has to do with limitations of the assignin() function, which
% unpackstruct() calls. To optimize speed, assignin() does not cross-check
% dynamically created variables with the list of available functions.
flds=enrow(fieldnames(S));
for fld=flds
fld=fld{:};
%%%Necessary to deal with a MATLAB limitation
s=evalin('caller',['which( ''' fld ''' )']);
if ~(isempty(s) || strcmp(s,'variable'))
str=['Variable name ''' fld];
str=[str, ''' corresponds to a function and, due to a MATLAB glitch, may not be recognized as a variable'];
warning(str)
end
assignin('caller',fld,getfield(S,fld));
end
*snip*
Don't do this! The problems you can cause when you try to "poof" variables
into a workspace like this have been discussed frequently in this newsgroup.
Best practice is to use the fields of the struct rather than trying to
create variables dynamically at runtime..
*snip*
> I run the test_explode function and I get this:
>
>>> test_explode
> foo =
> x: 1
> foo =
> x: 1
> debug: 1
> x is a variable.
> debug is a variable.
> x=1
> ??? Attempt to execute SCRIPT debug as a function:
> /pkg/matlab/r2008b/toolbox/matlab/codetools/debug.m
>
> Error in ==> test_explode at 8
> disp(['debug=' num2str(debug)])
>
>>>
>
>
> Can anyone help me solve this "non-problem"? I want to at least *be able
> to* use debug as a variable name in he sense I showed above. And I
> definitely do not want Matlab to lie to me (the result of "which" is
> wrong.)
MATLAB is not lying to you.
When you run your function, MATLAB needs to determine what each identifier
you use is as part of the process of parsing the function. At that time,
there's no indication in your code that debug should be a variable; however,
there is a function named debug. Therefore, MATLAB decides that the
instances of debug in the code should be calls to that function. When the
code is actually executed, a variable named debug is created, and WHICH
reflects that fact -- but at that point, it's too late for MATLAB to "change
its mind" and it tries to call the debug function on the last line. DEBUG
is a script file, though, and so you correctly receive an error.
This is why you SHOULD NOT "poof" variables into the workspace at runtime,
whether via EVALIN, ASSIGNIN, EVAL, or LOAD.
--
Steve Lord
sl...@mathworks.com
> This is why you SHOULD NOT "poof" variables into the workspace at runtime,
> whether via EVALIN, ASSIGNIN, EVAL, or LOAD.
LOAD as well? This would appear to rule out any runtime use of load() at all.
Doing this is bad:
function y = foo
load mymatfile.mat % contains a variable named plot
y = plot+2;
Doing this is not bad.
function y = foo2
S = load('mymatfile.mat'); % contains a variable named plot
y = S.plot + 2;
The former "poofs" a variable named plot into the foo function's workspace,
but the instance of plot on the next line has already been determined to be
a call to the PLOT function at parse-time.
The latter creates fields in the S variable at run-time, but that's okay --
since there's an instance of S on the left-hand side of an equals sign, it
had been classified as a variable when the function was parsed. There's no
"poofing" involved.
--
Steve Lord
sl...@mathworks.com