octavenested-functionfunction-handle

function handle to nested function not working for some values of parameter


This function is supposed to return a function handle to the nested function inside, but if the variable x is set to a negative value in the outer function, it doesn't work.

The inner nested function is just a constant function returning the value of the variable x that is set in the outer function.

function t=test(x)
    x=-1;
    function y=f()
        y=x;
    endfunction
    t=@f;
endfunction

If I try to evaluate the returned function, e.g. test()(3), I get an error about x being undefined. The same happens if x is defined as a vector with at least one negative entry or if x is argument of the function and a negative default value is used for evaluation. But if I instead define it as some nonnegative value

function t=test(x)
    x=1;
    function y=f()
        y=x;
    endfunction
    t=@f;
endfunction,

then the returned function works just fine. Also if I remove the internal definition of x and give the value for x as an argument to the outer function (negative or not), like

function t=test(x)
    function y=f()
        y=x;
    endfunction
    t=@f;
endfunction

and then evaluate e.g. test(-1)(3), the error doesn't occur either. Is this a bug or am misunderstanding how function handles or nested functions work?

The Octave documentation recommends using subfunctions instead of nested functions, but they cannot access the local variables of their parent function and I need the returned function to depend on the input of the function returning it. Any ideas how to go about this?


Solution

  • As of octave version 5.2.0 the nested function handles were not supported at all. I'm going to guess that is the novelty of the version 6.

    In octave functions are not variables, the engine compiles\translates them at the moment of reading the file. My guess would be that behavior you are observing is influenced by your current workspace at the time of function loading.

    The common way for doing what you are trying to do was to generate the anonymous (lambda) functions:

    function t = test1(x=-1)
        t = @()x;
    end
    function t = test2(x=-1)
        function s = calc(y,z)
            s = y + 2*z;
        end
        t = @(a=1)calc(a,x);
    end
    

    Note that default parameters for the generated function should be stated in lambda definition. Otherwise if you'd call it like test2()() it would not know what to put into a when calling calc(a,x).

    If you are trying to create a closure (a function with associated state), octave has limited options for that. In such a case you could have a look at octave's object oriented functionality. Classdef might be useful for quick solutions.