Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB bug? "Undefined function or variable" error when using same name for function and variable

It is occasionally convenient to use a function as a "constant" variable of sorts in MATLAB. But when I was using this feature recently, I ran into an unexpected error. When I run the MWE below, I get the error Undefined function or variable 'a'. despite the function being clearly available in the same file. When I comment out the if statement, the error goes away. This seems to imply that MATLAB is pre-interpreting a as a variable even though the variable assignment line is never reached, ignoring the fact that there is a function by the same name. Is this a MATLAB bug or is it somehow the desired behavior?

Here is the MWE:

function matlabBugTest(  )
    if false
        a = 'foo';
    end
    a
end
function b = a()
    b = 'bar';
end

Follow-up:

I know it seems weird to intentionally use the same name for a variable and a function, so I'll give an example of where this can be useful. For instance, you may want to use a function to store some constant (like a file path), but also want to be able to use a different value in case the function cannot be found. Such a case might look like:

if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));

I know that language design decisions are often difficult and complicated, but one of the more unfortunate consequences of MATLAB's choice here to ignore the function by the same name is that it breaks compatibility between functions and scripts/command line. For instance, the following runs without issue in a script:

if false
    a = 'foo';
end
a

where the function a (shown above) is saved in its own file.

like image 929
tarheels Avatar asked May 26 '16 23:05

tarheels


People also ask

Why am I getting unrecognized function or variable in MATLAB?

Accepted Answer MATLAB does not recognize the specified string as the name of a function on the MATLAB path or as a variable. "Undefined function or variable" can be caused by: 1) Trying to use a variable that has not been defined before this line of code executes. Undefined function or variable 'y'.

What does Unable to resolve the name mean in MATLAB?

This error occurs when the script 'filename. m' is run at Command Prompt, as the dot is interpreted as an operator. So MATLAB searches for a struct with the name 'filename' and a field 'm', instead of 'filename' script file.

Can you use undefined variables in MATLAB?

You can't use any undefined variables in Matlab.


2 Answers

It has to do with how Matlab performs name-binding at compilation time. Because matlabBugTest has a line that assigns a value to a, a is determined to be a variable, and the later line with a is a reference to that variable and not a call to the local function. More modern versions of Matlab, like my R2015a install, gives a more clear error message:

At compilation, "a" was determined to be a variable and this variable is uninitialized. "a" is also a function name and previous versions of MATLAB would have called the function. However, MATLAB 7 forbids the use of the same name in the same context as both a function and a variable.

It's not so much a bug, as it is an ambiguity introduced by the naming scheme that was given a default resolution method, which can be annoying if you have never encountered the problem before and m-lint doesn't mark it. Similar behavior occurs when variables are poofed into the workspace without initialization beforehand.

So the solution is to either change the name of the function or the variable to different things, which I would argue is good practice anyways.


In considering your follow-up example, I have noticed some interesting behavior in moving things around in the function. Firstly, if the function is either external or nested, you get the behavior discussed very well by Suever's answer. However, if the function is local, you can get around the limitation (at least you can in my R2014b and R2015a installs) by invoking the function prior to converting it to a variable as long as you initialize it or explicitly convert it to a variable at some point. Going through the cases, the following bodies of matlabBugTest perform thusly:

  • Fails:

    a
    if false
        a = 'foo';
    end
    a
    
  • Runs:

    a
    if true
        a = 'foo';
    end
    a
    
  • Runs:

    a = a;
    if false % runs with true as well.
        a = 'foo';
    end
    a
    

I'm not entirely sure why this behavior is the way it is, but apparently the parser handles things differently depending on the scope of the function and the order of what symbols appear and in what contexts.

So assuming this behavior hasn't and will not change you could try something like:

pathConstant = pathConstant;
if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));

Though, entirely personal opinion here, I would do something like

pathConstant = getPathConstant();
if ~exist('pathConstant.m', 'file')
    pathConstant = 'C:\some\path';
end
load(fullfile(pathConstant, 'filename.ext'));

Concerning breaking "compatibility between functions and scripts/command line", I don't really see this as an issue since those are two entirely different contexts when it comes to Matlab. You cannot define a named function on the command line nor in a script file; therefore, there is no burden on the Matlab JIT to properly and unambiguously determine whether a symbol is a function call or a variable since each line executes sequentially and is not compiled (aside from certain blocks of code the JIT is designed to recognize and optimize like loops in scripts). Now as to why the above juggling of declarations works, I'm not entirely sure since it relies on the Matlab JIT which I know nothing about (nor have I taken a compiler class, so I couldn't even form an academic reason if I wanted).

like image 180
TroyHaskin Avatar answered Oct 22 '22 03:10

TroyHaskin


The reason that you get this behavior is likely that Matlab never have implemented scope resolution for any of their statements. Consider the following code,

(a)

if true
    a = 'foo';
end
disp(a)

This would actually display "foo". On the other hand would,

(b)

if false
    a = 'foo';
end
disp(a)

give you the error Undefined function or variable "a". So let us consider the following example,

(c,1)

enterStatement = false;
if enterStatement
    a = 'foo';
end
disp(a)

(c,2)

enterStatement = mod(0,2);
if enterStatement
    a = 'foo';
end
disp(a)

TroyHaskin clearly states the following in his answer

It has to do with how Matlab performs name-binding at compilation time. Because matlabBugTest has a line that assigns a value to a, a is determined to be a variable, and the later line with a is a reference to that variable and not a call to the local function

Matlab does not support constant expressions and does only a limited amout of static code analysis. In fact, if the if statement takes argument false, or if enterStatement is false, Matlab provides a warning, This statement (and possibly following ones) cannot be reached. If enterStatement is set to false Matlab also generates another warning, Variable a is used, but might be unset. However if enterStatement = mod(0,2), so to say if enterStatement calls a function, you get no warning at all. This means that if the example in the question was allowed then (c,2) would compile based on how the function were evaluated and that is a contradiction. This would mean that the code would have to compile based on its runtime results.

Note: Sure it could be good if Matlab could generate an error in case the enterStatement was an expression instead of a constant false, but whether or not this is possible it would depend on implementation I guess.

like image 44
patrik Avatar answered Oct 22 '22 03:10

patrik