Nested functions variable scope

Hi,
I have been using the NLEIGS (for solving nonlinear eigenvalue problems):
https://twr.cs.kuleuven.be/research/software/nleps/nleigs.php

Basically the package consists of a small number of function with the main being obviously nleigs.

nleigs has a small number of nested functions, with one of them being residuals.

The residuals functions uses some variables from the outer scope, like Ahandle. E.g. Ahandle is a boolean/logical variable that only takes true or false values.
The issue is that when nsleig calls residuals the variable that outside take other values are shown in the nested function has empty cells {}. So Ahandle goes from true/false to {}.

The final result is that due to this code that would otherwise:

if Ahandle

fails as
error: invalid conversion from cell array to logical value

I though from reading Nested Functions (GNU Octave (version 6.2.0)) that this case was supported.

FWIW I am using the latest development version.

Could you please check if this is fixed for Octave 6.3?
That version isn’t actually released yet. But you can download a release candidate (version 6.2.92) from here:
alpha.gnu.org/gnu/octave

No it does not work:

error: invalid conversion from cell array to logical value
error: called from
nleigs>residual at line 1061 column 9
nleigs at line 343 column 13

The header says:
GNU Octave, version 6.2.93

I follow the octave repo and so I switched the branch and compiled.

Thank you,

Actually the code is more interesting, there is a twist, the residuals function is used in a function handle:

funres = @residual;

% compute residuals
res = funres(lam,X);

That is Octave 5 does not work on this code:
error: handles to nested functions are not yet supported
error: called from
nleigs>checkInputs at line 695 column 16
nleigs at line 79 column 22

Interestingly if I call the function directly, instead of using the function handle, then it works. This applies to Octave 6 as well as 7.

Should I report this as a bug or this already known?

Best regards.

Is there a simple test case?

From what I can tell, this is the structure

function mainfcn ()
  Ahandle = true;  # A boolean variable

  function r = nestfcn ()
    if (Ahandle)
      r = 1;
    else
      r = 0;
    end
  endfunction

  fcn_handle = @nestfcn;  # get a handle to nested function
  output = fcn_handle ()  # executed nested function

endfunction

This code works for me on the development branch.

I have been trying to build a minimal working example but I failed so far.

I am also using the development branch by default.

@Jose_Matos A small example is nice to have but not necessary. I downloaded nleigs but need to know exactly what code you use to generate the error.

@jwe: Thank you.
This is the minimal example that fails.

n = 10;

% solve the using nleigs
% ... polynomial matrices
BN = {};
% ... nonlinear matrices
CN{1} = eye(n); CN{2} = eye(n);
% ... nonlinear functions
fN{1} = @(x) 1; fN{2} = @(x) x;
% ... nlep structure
A = struct('B', {BN}, 'C', {CN}, 'f', {fN});
% ... parameters and options
sigma = [60, 70];
% ... compute solution
lambdan = nleigs(A, sigma);

Thanks for the info. I can reproduce the problem. Could you please open a bug report? The info needed there would be the link to nleigs and your test script. In any eventual fix, I could just link to this discussion but I think it would be more helpful to have a bug report if anyone searches for this problem in the future.

I don’t have a fix yet, but I think the problem is that when creating the funres handle to the nested residual function Octave is picking up the wrong function context. It makes the list of linked scopes residualcheckInputnleigs when checkInput should not appear in that list because residual is nested in nleigs, not checkInput.

@Jose_Matos I think the attached change will fix this problem. It would still be good to have a bug report to reference in the commit message. Probably this change should go on stable for the upcoming release.

nested-handle-diffs.txt (1.3 KB)

I think that I finally got a MWE without using nleigs. Actually I already had it last Friday, based on Rik’s example, my problem is that I did not had an error (by accident):

function mainfcn2 (varargin)

  [Ahandle, static, fcn_handle] = checkInput(varargin{:});  # A boolean variable
  output = fcn_handle ()  # executed nested function

  function [Ahandle, static, fcn_handle] = checkInput(varargin)
    %% initialize

    Ahandle = true;
    static = false;
    fcn_handle = @nestfcn;  # get a handle to nested function
  end

  function r = nestfcn ()
    if (islogical(Ahandle))
      disp("Success.")
    else
      fprintf("Something went wrong: Ahandle is a %s\n", class(Ahandle))
    end
    r = 1;
  end
end

The issue/bug here is that Ahandle becomes a function handle inside nestfcn. So something that I learned today is that for Octave a function handles can be evaluated as boolean while an empty cell can not.

So I think that this qualifies as a bug, I entered: GNU Octave - Bugs: bug #60845, Nested functions variable scope [Savannah]

BTW one question that I have from the messages above.
Why does not the last line works as the first two?

>> if (@sin) disp('OK') end
>> if ([]) disp('OK') end
>> if ({}) disp('OK') end
error: invalid conversion from cell array to logical value

@jwe With your patch applied I can confirm that all the examples presented work correctly now.
And yes, it would be nice to have this is Octave 6. :slight_smile:

Thank you :smiley:

I separately tested jwe’s patch and while it fixes the issue with inheritance of variables, it doesn’t fix a further issue with who which reports two copies of an inherited variable: one copy is local to the nested function and has the inherited value from the top-level function and the other is the name from the top-level function.

Matlab allows numeric arrays to be converted to logical values. In the old days, I remember the Matlab docs saying that the condition of an if or while statement is considered true if all elements are non-zero. However, that seemed at odds with all ([]) returning true vs. [] in the condition of an if or while statement being considered false. Now the Matlab docs say that the condition of an if or while statement is true if it is not empty and all elements are nonzero.

There is no similar conversion for cell arrays.

Conversion of function handles to logical values should probably also be an error. What do current versions of Matlab do?

Thank you for the explanation. It makes sense.
BTW I asked to a colleague to run that code and this was the outcome:

>> if (@sin) disp('OK') end

if (@sin) disp('OK') end
                      ↑
Error: Illegal use of reserved keyword "end".

>> if (@sin) disp('OK'), end
Conversion to logical from function_handle is not possible.