How does scoping in Matlab work?

2019-02-12 07:18发布

问题:

I just discovered (to my surprise) that calling the following function

function foo()
if false
   fprintf = 1;
else
  % do nothing
end
fprintf('test')

gives and error Undefined function or variable "fprintf". My conclusion is that the scope of variables is determined before runtime (in my limited understanding how interpretation of computer languages and specifically Matlab works). Can anyone give me some background information on this?

Edit

Another interesting thing I forgot to mention above is that

function foo()
if false
   fprintf = 1;
else
  % do nothing
end
clear('fprintf')
fprintf('test')

produces Reference to a cleared variable fprintf.

回答1:

MATLAB parses the function before it's ever run. It looks for variable names, for instance, regardless of the branching that activates (or doesn't activate) those variables. That is, scope is not determined at runtime.

ADDENDUM: I wouldn't recommend doing this, but I've seen a lot of people doing things with MATLAB that I wouldn't recommend. But... consider what would happen if someone were to define their own function called "false". The pre-runtime parser couldn't know what would happen if that function were called.



回答2:

It seems that the first time the MATLAB JIT compiler parses the m-file, it identifies all variables declared in the function. It doesn't seem to care whether said variable is being declared in unreachable code. So your local fprintf variable immediately hides the builtin function fprintf. This means that, as far as this function is concerned, there is no builtin function named fprintf.

Of course, once that happens, every reference within the function to fprintf refers to the local variable, and since the variable never actually gets created, attempting to access it results in errors.

Clearing the variable simply clears the local variable, if it exists, it does not bring the builtin function back into scope.

To call a builtin function explicitly, you can use the builtin function.

builtin( 'fprintf', 'test' );

The line above will always print the text at the MATLAB command line, irrespective of local variables that may shadow the fprintf function.



回答3:

Interesting situation. I doubt if there is detailed information available about how the MATLAB interpreter works in regard to this strange case, but there are a couple of things to note in the documentation...

The function precedence order used by MATLAB places variables first:

Before assuming that a name matches a function, MATLAB checks for a variable with that name in the current workspace.

Of course, in your example the variable fprintf doesn't actually exist in the workspace, since that branch of the conditional statement is never entered. However, the documentation on variable naming says this:

Avoid creating variables with the same name as a function (such as i, j, mode, char, size, and path). In general, variable names take precedence over function names. If you create a variable that uses the name of a function, you sometimes get unexpected results.

This must be one of those "unexpected results", especially when the variable isn't actually created. The conclusion is that there must be some mechanism in MATLAB that parses a file at runtime to determine what possible variables could exist within a given scope, the net result of which is functions can still get shadowed by variables that appear in the m-file even if they don't ultimately appear in the workspace.


EDIT: Even more baffling is that functions like exist and which aren't even aware of the fact that the function appears to be shadowed. Adding these lines before the call to fprintf:

exist('fprintf')
which('fprintf')

Gives this output before the error occurs:

ans =
     5
built-in (C:\Program Files\MATLAB\R2012a\toolbox\matlab\iofun\fprintf)

Indicating that they still see the built-in fprintf.



回答4:

These may provide insight:

  • https://www.mathworks.com/help/matlab/matlab_prog/base-and-function-workspaces.html
  • https://www.mathworks.com/help/matlab/matlab_prog/share-data-between-workspaces.html

This can give you some info about what is shadowed:

which -all

(Below was confirmed as a bug) One gotcha is that Workspace structs, and classes on the path, have particular scoping and type precedence that (if you are me) may catch you out.

E.g. in 2017b:

% In C.m, saved in the current directory
classdef C
 properties (Constant)
   x = 100;
 end
end

% In Command window
C.x = 1;
C.x       % 100
 C.x      % 1 (Note the space)
C.x*C.x   % 1
disp(C.x) % 1


标签: matlab scope