Need help understanding Matlab behavior

Related to bug #60845 I’m trying to understand what Matlab displays for who vs. whos in the scope of a nested function call. Could someone please try running the attached function in a recent version of Matlab and reply with the output it produces?

mainfcn.m (487 Bytes)

Matlab R2021a

>> mainfcn
WHO IN NESTED FUNCTION:


Your variables are:

Ahandle     fcn_handle  static      varargin    

WHOS IN NESTED FUNCTION:

  Name            Size            Bytes  Class              Attributes

  Ahandle         1x1                 1  logical                      
  fcn_handle      1x1                32  function_handle              
  static          1x1                 1  logical                      
  varargin        0x0                 0  cell                         


ans =

  logical

   1

Oh, I think that wasn’t the best test function. Try this version instead?

mainfcn.m (668 Bytes)

>> mainfcn
WHO IN NESTED FUNCTION:


Your variables are:

nestfcn_local_var  Ahandle            fcn_handle         main_fcn_var       static             varargin           

WHOS IN NESTED FUNCTION:

  Name                   Size            Bytes  Class              Attributes

  ---- mainfcn/nestfcn ------------------------------------------------------
  nestfcn_local_var      1x1                 8  double                       

  ---- mainfcn --------------------------------------------------------------
  Ahandle                1x1                 1  logical                      
  fcn_handle             1x1                32  function_handle              
  main_fcn_var           1x1                 8  double                       
  static                 1x1                 1  logical                      
  varargin               0x0                 0  cell                         

WHO IN NESTED FUNCTION:


Your variables are:

nestfcn_local_var  Ahandle2           fcn_handle2        output             static2            
Ahandle            fcn_handle         main_fcn_var       static             varargin           

WHOS IN NESTED FUNCTION:

  Name                   Size            Bytes  Class              Attributes

  ---- mainfcn/nestfcn ------------------------------------------------------
  nestfcn_local_var      1x1                 8  double                       

  ---- mainfcn --------------------------------------------------------------
  Ahandle                1x1                 1  logical                      
  Ahandle2               1x1                 1  logical                      
  fcn_handle             1x1                32  function_handle              
  fcn_handle2            1x1                32  function_handle              
  main_fcn_var           1x1                 8  double                       
  output                 1x1                 1  logical                      
  static                 1x1                 1  logical                      
  static2                1x1                 1  logical                      
  varargin               0x0                 0  cell                         


ans =

  logical

   1


ans =

  logical

   1

Thanks for testing. I have one more variation to try:

mainfcn.m (487 Bytes)

>> mainfcn
WHO IN NESTED FUNCTION:


Your variables are:

r           Ahandle     fcn_handle  static      varargin    

WHOS IN NESTED FUNCTION:

  Name            Size            Bytes  Class              Attributes

  ---- mainfcn/nestfcn -----------------------------------------------
  r               1x1                 1  logical                      

  ---- mainfcn -------------------------------------------------------
  Ahandle         1x1                 1  logical                      
  fcn_handle      1x1                32  function_handle              
  static          1x1                 1  logical                      
  varargin        0x0                 0  cell                         


ans =

  logical

   1

Thanks. I think I understand what’s happening now. It should be possible to make Octave’s output closer to Matlab’s here but I think any changes for who and whos can go on default.

For anyone looking here later, the fix for who and whos was fairly simple and was applied to stable in this changeset:

http://hg.savannah.gnu.org/hgweb/octave/rev/2bb72743d3eb

I would like to know what Matlab does when parsing the attached functions.

The question is whether, when parsing a function file that has subfunctions without end statements (f1.m), are variables that have appeared in assignment expressions recognized as variables in the subfunctions even though eventually, after all the parsing is done, they are not actually variables in the scope of the subfunction. But if there are no end statements, then it seems to me that when parsing the subfunctions, they actually look like nested functions. And in that case, the variables defined in the main function would be visible in the nested function (see f2.m). So, does Matlab do something special to handle this case, or is it just something that users are supposed to avoid doing? And, does the behavior change if the functions and subfunctions have end statements (f3.m)

Download the files and try executing f1, f1, and f3 and report the results here.

f1.m (374 Bytes)
f2.m (293 Bytes)
f3.m (217 Bytes)

In Matlab R2021a:

>> f1
foo =
    13
whos =
     1
>> f2
Error: File: f2.m Line: 9 Column: 5
Using identifier 'whos' as both a variable and a command is not supported. For more information, see "How
MATLAB Recognizes Command Syntax". 
>> f3
foo =
    13
whos =
     1

@siko1056: Thanks for the info.

OK I expected f2 to fail and f3 to succeed.

I wasn’t sure what would happen with f1. Behavior identical to f3 is good, I suppose. But when parsing, how do you know whether sub is a subfunction instead of a nested function before you get to the end of the file and find that there are no end tokens to match the function tokens? I don’t think that’s easy to do with the kind of parser we are generating with Bison.

EDIT: After some more thought, it might be possible to always consider an identifier at the beginning of a statement as a possible command when parsing a function and parse it that way regardless of the status of any symbols that appear to be variables. Then, after the file is completely parsed and subfunctions and nested function scopes have been sorted out, walk the parse trees of the functions defined in the file and detect any command-style function calls that are using a symbol name that has previously appeared to be used as a variable. If I have some free time I’ll take a look at doing that.

1 Like

Here’s another question about command syntax vs. variables: do both of the following fail with the error shown in Need help understanding Matlab behavior - #11 by siko1056 or does it only fail if whos is defined as a variable before using it in a command-style function call?

function f ()
  whos = 13;
  whos x
end
function f ()
  whos x
  whos = 13;
end

Again Matlab R2021a

Error: File: f.m Line: 3 Column: 3
Using identifier 'whos' as both a variable and a command is not supported. For more information, see "How
MATLAB Recognizes Command Syntax".
Error: File: f.m Line: 2 Column: 3
Using identifier 'whos' as both a variable and a command is not supported. For more information, see "How
MATLAB Recognizes Command Syntax".

Therefore, I think Matlab does the same as you suggested:

I think Octave behavior agrees with Matlab after this change:

http://hg.savannah.gnu.org/hgweb/octave/rev/e2e493712818

Octave can now detect the use of a symbol as both a variable and a command when a function is parsed regardless of the order (variable or command first) and it does the check after the file is fully parsed by walking the parse tree so it is not fooled by subfunctions that have no end statements.

This change and the two before it also set up the possibility of doing all semantic checks after a file is parsed so we can issue a list of errors and warnings for all problems found instead of just failing at the first problem. We might also be able to do the same for some syntax errors if we improve error recovery in the parser.

1 Like

For the attached MEX function, what does Matlab do for

a = [1,2;3,4];
b = a;
mxtst (a)
a
b

? Do a and b remain unchanged?

mxtst.c (284 Bytes)

Of course not :upside_down_face:

>> a

a =

    13     2
     3     4

>> b

b =

    13     2
     3     4

I use some code that rely on this - highly discouraged but convenient…

@Guillaume Thanks.

Using the attached function and script, could someone please try the following with a recent version of Matlab and report the results? Save both files in the same directory and execute test_mkfh.

mkfh.m (220 Bytes)

test_mkfh.m (57 Bytes)

>> test_mkfh

fh =

  function_handle with value:

    @mkfh/f2


ans =

    24


info = 

  struct with fields:

     function: 'mkfh/f2'
         type: 'nested'
         file: 'C:\Users\nicholas.jankowski\Desktop\temp\test\mkfh.m'
    workspace: {[1×1 struct]}


ans =

  1×1 cell array

    {1×1 struct}

Thanks. Now what happens if instead of nested functions we use anonymous functions as in the attached version of mkfh.m?

mkfh.m (118 Bytes)

Also, can you show the full contents of the workspace cell array in both cases?