Why am I warned about defining variables in a nested function, when I don't?

6 views (last 30 days)
  1. EDIT: The following is an newer and simpler description of the problem:
Every time I run my function warnTest(), I receive a warning about defining the variable "ind" in the nested function. But I don't define the variable "ind" in the nested function. The warning doesn't seem to be true.
Furthermore, why am I not warned about the variable "n", which is also defined in the parent function and shared with the nested function, just like the variable "ind"?
function warnTest()
% % warnTest() reproduces the following warnings:
%
% Warning: File: /path/to/warnTest.m Line: 27 Column: 29
% Defining "ind" in the nested function shares it with the parent function. In a future release, to share "ind" between parent and nested functions, explicitly define it in the parent function.
% Warning: File: /path/to/warnTest.m Line: 27 Column: 42
% Defining "ind" in the nested function shares it with the parent function. In a future release, to share "ind" between parent and nested functions, explicitly define it in the parent function.
%
% However, warnTest() doesn't define the variable "ind" in the nested
% function, as suggested by the warning message.
%
% Additionally, warnTest() also defines the variable "n" in the parent
% function and shares it with its nested function. However, MATLAB issues
% no warning about the variable "n".
%
% This behaviour has been observed in the following MATLAB Releases:
%
% MATLAB® R2018a Update 6 (9.4.0.949201) 64-bit (maci64) September 5, 2018
% MATLAB® Version: 9.6.0.1150989 (R2019a) Update 4 64-bit Windows 10
% Define labels for divisor and dividend
f = ["a","a","a","a","a","b","b","b","b","b"];
l = numel(f);
k = unique(f);
n = numel(k);
m = 7;
p = 5;
% Define divisor and dividend
A = randi(100,m,l);
B = randi(100,p,l);
% Define var ind in parent function
for ii = n:-1:1
ind{ii} = find(k(ii) ~= f);
end
C = nestFun(A,B);
disp(C);
% Define nested function
function [Z] = nestFun(X,Y)
for jj = n:-1:1
Z(:,:,jj) = X(:,ind{jj})/Y(:,ind{jj});
end
end
end
  1. EDIT: The following is an older, slightly more complicated description of the problem:
Every time I run my parentFunction.m, I receive 2 warnings like the following:
Warning: File: /path/to/my/parentFunction.m Line: 439 Column: 34
Defining "train_ind" in the nested function shares it with the parent function. In a future release, to share "train_ind" between parent and nested functions, explicitly define it in the
parent function.
> In callerFunction (line 76)
Warning: File: /path/to/my/parentFunction.m Line: 439 Column: 59
Defining "train_ind" in the nested function shares it with the parent function. In a future release, to share "train_ind" between parent and nested functions, explicitly define it in the
parent function.
> In callerFunction (line 76)
However, the variable "train_ind" is explicitly defined in the parent function, before the nested function is first called.
So, why would I receive that warning, if it doesn't apply to my function?
(Then again, the warning is thrown in the callerFunction, in the line 76 which calls the parentFunction.m. Should that make a difference?)
My release: MATLAB® R2018a Update 6 (9.4.0.949201) 64-bit (maci64) September 5, 2018
The parentFunction.m is fairly long, so I'll show you the relevant lines only.
  • In line 241 I first define the variable in question:
% Build training & testing index for cross-validation
for ii = n_folds:-1:1
train_ind{ii} = find(k(ii) ~= folds);
test_ind{ii} = find(k(ii) == folds);
end
  • In line 256 I first call the nested function:
% Train encoding model for the entire brain
weights(:,:,:,ff) = IEM_train(betas, des(:,:,ff));
  • In line 429 I define the nested function:
function [weights] = IEM_train(betas, des_mat)
% Train encoding model with cross-validation
% Initialise weights
weights = NaN(n_vert,n_chans,n_folds);
% Loop over cross-validation folds
for nn = n_folds:-1:1
% Compute weights for each fold
weights(:,:,nn) = betas(mask,train_ind{nn})/des_mat(:,train_ind{nn});
end
end
  6 Comments
JMM
JMM on 23 Sep 2020
@John D'Errico My release: MATLAB® R2018a Update 6 (9.4.0.949201) 64-bit (maci64) September 5, 2018
Rik
Rik on 24 Sep 2020
My copy (R2020a_u5 on W10) doesn't return any warning (mlint or otherwise) when running your example function.

Sign in to comment.

Accepted Answer

Andreas Apostolatos
Andreas Apostolatos on 25 Sep 2020
Edited: Andreas Apostolatos on 26 Sep 2020
Hello everyone,
It appears so, that this warning does not persist for release R2019b and later releases when cell array 'ind' is implicitly initialized as in the provided code.
The trigger of this warning in the prior to R2019b releases seems to be the fact that cell array 'ind' is not explicitly initialized in the parent function.
By explicitly initializing array 'ind' before the loop where its elements are being assigned in the parent function, namely,
ind = cell(n, 1);
for ii = n:-1:1
ind{ii} = find(k(ii) ~= f);
end
the warning disappears also in the releases prior to R2019b.
Best Regards,
Andreas
  3 Comments
John D'Errico
John D'Errico on 26 Sep 2020
This now makes sense. Many thumbs up to Andreas for explaining this. The simple answer is thus to upgrade MATLAB, but the other takeaway is to always preallocate grown arrays. And we should be doing that anyway.

Sign in to comment.

More Answers (2)

Bjorn Gustavsson
Bjorn Gustavsson on 23 Sep 2020
Because nested functions share the name-space with its parrent function. That is all variables in the parrent function are available in the nested function - pretty much as global variables. Apparently variables defined in a nested function also become available in its parrent function.
(There might be good use-cases for nested functions, but the "global" nature (between parrent and nested function) of the variables made me stay away from nested functions - it is, in my experience, possible to get by with sub-functions in all cases. The global-nature will obvoiusly come with similar problems as global variables in general - they might randomly change variables rather far away from where the problems arise, which makes debugging challenging. It took me some 15-20 years to weed out global variables from a toolbox I started with before I learnt how much problems they might cause. To be fair for the nested functions the problem is way more contained than for global variables in general. But, again "in my opinion", the problem is of the same character, and you have at least a 400-lines file. I guess the warning is there to tell you what will/might happen in future releases. I'd switch to a subfunction - but you might very well have good reasons for using a nested function...)
HTH
  10 Comments
JMM
JMM on 23 Sep 2020
I have adapted the title of my question to reflect the oddity, that MATLAB sends me a warning about something which does not seem to be the case.
Bjorn Gustavsson
Bjorn Gustavsson on 23 Sep 2020
@Stephen: and it seems to vary a bit between versions, in my first version the variable x deeper in limbo than a variable specified with persistent that's not been assigned to anything...
@JMM: for that use I stick to sub-functions and bear the burden of the longer argument-lists - and have the relief to know that I don't have to worry about peculiar side-effects of my functions (and with matlabs call-by-reference-until-modified I'm under the impression that there is not much additional overhead.)

Sign in to comment.


Stephen23
Stephen23 on 23 Sep 2020
Edited: Stephen23 on 23 Sep 2020
So far no one has actually explained the warning, which is a pity because this is really quite an interesting question.
Some answers/comments have explained the basic concept of nested functions (Surprise! Nested functions can share variables between workspaces!), but so far no one has actually put forward a plausible explanation of this warning in the context given in the question.
Here are a few possible explanations of this strange warning:
  • Some version-specific warning. Perhaps it was decided to remove this (rather superfluous?) warning, so it only appeared in one/a few releases.
  • Some special syntax that confuses the mlint parser, so that it cannot recognize that the variable is also defined in the parent workspace. For example, does the code include any (awful, anti-pattern) magic like eval, assignin, or any debugging commands? Does the code use cells or anything similar? Is it written in a script?
  • Is the variable name also the name of a function? Check using which.
  • Spelling. Yes, really. For example, it is very easy to miss a different character case: is it really x defined in the parent workspace, or is it X ? You can use the syntax highlighting to help check this: https://www.mathworks.com/help/matlab/matlab_prog/check-variable-scope-in-editor.html
If you want more help on this please tell us the exact MATLAB release you are using and upload the code.
EDIT: as little bit of internet searching found this, which might be related:
https://www.mathworks.com/help/matlab/release-notes-R2017b.html -> Language and Programming -> Functionality being removed or changed -> "Sharing uninitialized variables between a nested function and the parent function"
  7 Comments
JMM
JMM on 24 Sep 2020
Edited: JMM on 24 Sep 2020
@Stephen Cobeldick: I wrote a simpler function which reproduces my problem on two different installations & systems. I have added it to the top of my question. It doesn't seem to be related to eval(), assignin(), debugging settings, or code sections. I have also submitted a bug report to Mathworks.
Stephen23
Stephen23 on 24 Sep 2020
@JMM: good work on eliminating those possibilities. So far it really does seem that a (recently introduced) warning is either a) worded incorrectly and needs to be re-written, or b) is being shown as a result of a false-positive match by the mlint parser. I tried your example on earlier versions of MATLAB, with no warning.

Sign in to comment.

Categories

Find more on Loops and Conditional Statements in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!