Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

Thread Subject:
Parse problem in nested function

Subject: Parse problem in nested function

From: Kevin Sheppard

Date: 25 Oct, 2008 17:06:01

Message: 1 of 6

I am having a problem where a defined variable in the scope of a function is not being called and instead a function with the same name (date) is being called.

I tried to make the example below as close as possible to my actual function, including the use of uint32 data. Running this function produces an error even though "which date" and "whos date" both see date as a variable.

I have found a temporary workaround which is to initialize date as empty and then to check whether it is non-empty in my code, although as far as I can tell my code is legal and the parser is making a mistake in assuming that date is a function.

Unfortunately I can't easily get around this problem because I am reading in irregularly formatted text files where the header of the text file is used to provide variable names and so it is not practical to avoid function collisions.

A better workaround may be to eval anything of this type which also seems to work.

Have I done something illegal, or is the parser making an aggressive but unsafe optimization (this is on R2007a)?

Thanks,
Kevin


Example code:

function parseError

fields = {'date','data'};
values = uint32([20080705;121212]);

for i=1:length(fields)
    eval([fields{i} ' = uint32(10);'])
end

if exist('date','var')
    disp('date is a variable according to exist')
end
whos
which date
eval('date')
date(1)

Subject: Parse problem in nested function

From: Thomas Clark

Date: 25 Oct, 2008 19:44:02

Message: 2 of 6

Kevin,

Took me about 2 minutes to find this using MATLAB's documentation - you could have found it in less time than it took you to write your post.

Also, this is nothing to do with nested functions.

Rant over. I've revised your code (below) in two different ways - one as recommended by the documentation (which then disallows the use of the date function), another which avoids this confusion in the first place, and allows subsequent use of the date function.

*****************************

Variables used in evaluation statements such as eval, evalc, and evalin can be mistaken for function names. The following M-file defines a variable named length that conflicts with MATLAB length function:

function find_area
eval('length = 12; width = 36;');
fprintf('The area is %d\n', length .* width)

The second line of this code would seem to establish length as a variable name that would be valid when used in the statement on the third line. However, when MATLAB parses this line, it does not consider the contents of the string that is to be evaluated. As a result, MATLAB has no way of knowing that length was meant to be used as a variable name in this program, and the name defaults to a function name instead, yielding the following error:

find_area
??? Error using ==> length
Not enough input arguments.

To force MATLAB to interpret length as a variable name, use it in an explicit assignment statement first:

function find_area
length = [];
eval('length = 12; width = 36;');
fprintf('The area is %d\n', length .* width)

********************************



So to fix your code...

Example code # 1:

function parseError

date = [];
data = [];

fields = {'date','data'};
values = uint32([20080705;121212]);

for i=1:length(fields)
    eval([fields{i} ' = uint32(10);'])
end


Example code #2:

function parseError

fields = {'date','data'};
values = uint32([20080705;121212]);

for i=1:length(fields)
    % declares and renames read-in variables with
    % the prefix 'input_var_'
    eval(['input_var_' fields{i} ' = uint32(10);'])
end

Subject: Parse problem in nested function

From: Kevin Sheppard

Date: 26 Oct, 2008 00:01:02

Message: 3 of 6

I just didn't look for the right thing in the doc.

Before you rant you could at least read my post, where I state your first solution is not viable in my situation since it is not always the case that variable names wil be known before run time -- and hence I cannot declare all possible functions I may use -- and the second isn't viable because preserving the names of the variables is important since this is code that reads a particular data file structure that cannot be read using standard input mechanisms.

The solution, which I alluded to in in my post, is to never treat variables that are created with an eval statement using anything other then an eval statement. This disables the MATLAB's parser in the relevant context, although I question whether it is reasonable to use aggressive optimization in the presence of eval commands (which are going to be slow anyway).

Thanks though,
Kevin

"Thomas Clark" <t.clark@remove.spamcantab.net> wrote in message <gdvsu2$5bv$1@fred.mathworks.com>...
> Kevin,
>
> Took me about 2 minutes to find this using MATLAB's documentation - you could have found it in less time than it took you to write your post.
>
> Also, this is nothing to do with nested functions.
>
> Rant over. I've revised your code (below) in two different ways - one as recommended by the documentation (which then disallows the use of the date function), another which avoids this confusion in the first place, and allows subsequent use of the date function.
>
> *****************************
>
> Variables used in evaluation statements such as eval, evalc, and evalin can be mistaken for function names. The following M-file defines a variable named length that conflicts with MATLAB length function:
>
> function find_area
> eval('length = 12; width = 36;');
> fprintf('The area is %d\n', length .* width)
>
> The second line of this code would seem to establish length as a variable name that would be valid when used in the statement on the third line. However, when MATLAB parses this line, it does not consider the contents of the string that is to be evaluated. As a result, MATLAB has no way of knowing that length was meant to be used as a variable name in this program, and the name defaults to a function name instead, yielding the following error:
>
> find_area
> ??? Error using ==> length
> Not enough input arguments.
>
> To force MATLAB to interpret length as a variable name, use it in an explicit assignment statement first:
>
> function find_area
> length = [];
> eval('length = 12; width = 36;');
> fprintf('The area is %d\n', length .* width)
>
> ********************************
>
>
>
> So to fix your code...
>
> Example code # 1:
>
> function parseError
>
> date = [];
> data = [];
>
> fields = {'date','data'};
> values = uint32([20080705;121212]);
>
> for i=1:length(fields)
> eval([fields{i} ' = uint32(10);'])
> end
>
>
> Example code #2:
>
> function parseError
>
> fields = {'date','data'};
> values = uint32([20080705;121212]);
>
> for i=1:length(fields)
> % declares and renames read-in variables with
> % the prefix 'input_var_'
> eval(['input_var_' fields{i} ' = uint32(10);'])
> end

Subject: Parse problem in nested function

From: Kevin Sheppard

Date: 26 Oct, 2008 00:10:05

Message: 4 of 6

I should also admit that I was being lazy using evals. I've now refactored using only cell arrays for storing boht dat and variable names with a final assignment immediately prior to saving, and so I don't run into this issue.

Subject: Parse problem in nested function

From: Walter Roberson

Date: 26 Oct, 2008 00:41:13

Message: 5 of 6

Kevin Sheppard wrote:
> I should also admit that I was being lazy using evals. I've now refactored using only cell
> arrays for storing boht dat and variable names with a final assignment immediately prior
> to saving, and so I don't run into this issue.

You do not need, and should avoid, the final assignment before saving. Instead
you should use the solution hinted at in Thomas's second solution: a structure.
If, for example, you have the cell array VarStuff with VarStuff{K,1} being the variable
name from the data file, and VarStuff{K,2} being the corresponding value, then

TheStruct = cell2struct(VarStuff(:,2), VarStuff(:,1), 1);
save(TheFileName, '-struct', 'TheStruct')


>> help save

    SAVE FILENAME -STRUCT S saves the fields of the scalar structure S as
    individual variables within the file FILENAME.


And when you go to load the file, use the assignment form of load,

TheStruct = load(TheFileName);

which will create each individual variable within TheFileName as a field in
the structure TheStruct. It is, for example, perfectly safe to reference

TheStruct.date

without concern about whether the date() function will be invoked.

You can find the filenames of the structure using fieldnames(). You can
also do things like:

fn = fieldnames(TheStruct);
parmtot = 0;
for K = 1 : length(fn)
  if length(fn{K}) > 4 && strcmp(fn{K}(1:4), 'parm')
    parmtot = parmtot + TheStruct.(fn{K});
  end
end

Subject: Parse problem in nested function

From: Steven Lord

Date: 27 Oct, 2008 03:44:23

Message: 6 of 6


"Kevin Sheppard" <kevin.you.know.what.to.do.sheppard@economics.ox.ac.uk>
wrote in message news:gdvjlp$kii$1@fred.mathworks.com...
>I am having a problem where a defined variable in the scope of a function
>is not being called and instead a function with the same name (date) is
>being called.
>
> I tried to make the example below as close as possible to my actual
> function, including the use of uint32 data. Running this function
> produces an error even though "which date" and "whos date" both see date
> as a variable.
>
> I have found a temporary workaround which is to initialize date as empty
> and then to check whether it is non-empty in my code, although as far as I
> can tell my code is legal and the parser is making a mistake in assuming
> that date is a function.

There's nothing in your code that indicates to the parser that date should
be a variable. [The parser does not try to parse the strings you pass to
EVAL to determine whether or not something's a function; indeed, that's not
always an option. If you prompted the user to enter a string using INPUT
and then EVALed that, the parser would have no way of knowing what the user
will type in at runtime. Neither the Mind Reading Toolbox nor the Time
Travel Toolbox are ready yet.] Since there's a function called date, when
the parser sees your use of date in the code at parse time, it decides that
date must be the function. At runtime, when you try to create the date
variable, it's too late for MATLAB to change its mind.

This is one of the reasons that EVAL is generally considered evil and its
use is discouraged.

> Unfortunately I can't easily get around this problem because I am reading
> in irregularly formatted text files where the header of the text file is
> used to provide variable names and so it is not practical to avoid
> function collisions.

Instead of "poofing" variables into the workspace at runtime using EVAL or
LOAD, the preferred method is to create fields of a struct instead. Use
dynamic field names instead of EVAL or call LOAD with an output argument
instead of calling it with no output arguments.

http://www.mathworks.com/access/helpdesk/help/techdoc/matlab_prog/f2-88951.html#f2-41859.

> A better workaround may be to eval anything of this type which also seems
> to work.
>
> Have I done something illegal, or is the parser making an aggressive but
> unsafe optimization (this is on R2007a)?

Option 3 -- you're changing the rules of the game at runtime, invalidating
the decisions the parser made when it parsed the M-file.

> Thanks,
> Kevin
>
>
> Example code:
>
> function parseError
>
> fields = {'date','data'};
> values = uint32([20080705;121212]);
>
> for i=1:length(fields)
> eval([fields{i} ' = uint32(10);'])
> end
>
> if exist('date','var')
> disp('date is a variable according to exist')
> end
> whos
> which date
> eval('date')
> date(1)

The way I'd write your example code:


function noParseError
fields = {'date', 'data'};
values = uint32([20080705; 121212]);
for k = 1:length(fields)
    S.(fields{k}) = uint32(10);
end
if isfield(S, 'date')
    disp('date is a field of the struct S')
end
S.date(1)
T = load('mymatfile.mat'); % assume that T contains a variable named plot
T.plot
% If I had used load('mymatfile.mat') with no inputs, then tried to just say
"plot"
% MATLAB would have complained, as it would think I'd tried to call the
% PLOT function with 0 input arguments


The parser can tell that S and T are variables, and S.(<something>) is a
reference to a field of S. It doesn't need to know what <something> is at
parse time; you can choose what <something> is at runtime.

My version of your example code makes no assumptions except that the
variables you were creating have names that are valid structure field names
[and if they weren't, they wouldn't be valid variable names either.]

--
Steve Lord
slord@mathworks.com

Tags for this Thread

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Contact us