Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

behavior of assignin

523 views
Skip to first unread message

Henrik Holst

unread,
Feb 16, 2009, 12:45:07 PM2/16/09
to
Hi Matlab gurus!

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

Matt

unread,
Feb 16, 2009, 1:25:03 PM2/16/09
to
Henrik Holst <ho...@nada.kth.se> wrote in message
>
> 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.)

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

Steven Lord

unread,
Feb 16, 2009, 2:19:43 PM2/16/09
to

"Henrik Holst" <ho...@nada.kth.se> wrote in message
news:Pine.SOC.4.64.09...@my.nada.kth.se...

> Hi Matlab gurus!
>
> 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.

*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


Matt

unread,
Feb 16, 2009, 2:42:01 PM2/16/09
to
"Steven Lord" <sl...@mathworks.com> wrote in message <gnce8f$14v$1...@fred.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.


Steven Lord

unread,
Feb 16, 2009, 3:53:20 PM2/16/09
to

"Matt " <x...@whatever.com> wrote in message
news:gncfi9$puj$1...@fred.mathworks.com...

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


0 new messages