6

So, I'm applying for a job and need to figure out how nested functions work. To be more specific, I would like to know exactly how the following example posted by gnovice works.

The question is:

Given the following function, what will the output be when entering the code below in the command window?

function fcnHandle = counter
  value = 0;
  function currentValue = increment
    value = value+1;
    currentValue = value;
  end
  fcnHandle = @increment;
end

f1 = counter();
f2 = counter();
output = [f1() f1() f2() f1() f2()];  %# WHAT IS IT?!

I'm not applying for a job, and I'm able to figure out the answer to the question. I also find the answer from Mohsen to this question intuitive (find the size of a matrix without calling built-in functions). However, I can't help but hearing Albert Einstein's voice in my head.

enter image description here

I think the documentation was a bit messy, so I would be very happy if someone is able to explain how it works.

Community
  • 1
  • 1
Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70

3 Answers3

5

This use of nested functions is relevant for memoization (for additional reading see: use nested functions to memoize costly functions), since it exploits parametric function handles which store the value of the parameters at creation.

There are two things you need to notice:

  1. counter() returns a function handle directly to the nested function

    f1 = counter()
    f1 = 
       @counter/increment
    
  2. The nested function will 'save' the scoped variables. Refer to functions() for details.

    s = functions(f1)
    s = 
         function: 'counter/increment'
             type: 'nested'
             file: '\\ic.ac.uk\homes\ok1011\MATLAB\counter.m'
        workspace: {[1x1 struct]}
    

    with the scoped workspace retaining:

    s.workspace{1}
    ans = 
        fcnHandle: @counter/increment
            value: 0
    

Basically, counter() initializes the value to zero, and successive calls to @counter/increment will perform value = value+1;.

Finally, @counter/increment is assigned to f1 and all f1() is doing is @counter/increment() on the previously initialized value. Initializing f2 = counter(), creates another counter with a separate saved workspace.

Oleg
  • 10,406
  • 3
  • 29
  • 57
4

Let me try....

Each time the function counter() its called creates an unique function handle. This function handle is a handle to a function called increment, that takes its own variable value, and increments its by one.

So if called twice, like in the code (f1, f2) each time will return the same function (increment) but different handles. You have the function defined TWICE. And each of them now work independently. As this specific function (increment) relies in a saved internal value for its computation, you can observe how if called as in your code sample, outputs [1 2 1 3 2].

A good way of seing the differences better is to redefine the function as:

function fcnHandle = counter(val)
  value = val;
  function currentValue = increment
    value = value+1;
    currentValue = value;
  end
  fcnHandle = @increment;
end

and calling it like:

>> f1 = counter(0);
>> f2 = counter(1000);
>> output = [f1() f1() f2() f1() f2()]  %# WHAT IS IT?

Now, you will see that the output is [1 2 1001 3 1002]

Makes more sense now?

This code is created so it exploits this attribute of function handles (its the same thing, but its copied twice).

Stewie Griffin
  • 14,889
  • 11
  • 39
  • 70
Ander Biguri
  • 35,140
  • 11
  • 74
  • 120
2

Neat exercise. I never used nested functions with handles before, so here is my thought process: I found this paragraph in the manual very instructive:

Nested functions can use variables from three sources:

Input arguments

Variables defined within the nested function

Variables defined in a parent function, also called externally scoped variables

When you create a function handle for a nested function, that handle stores not only the name of the function, but also the values of externally scoped variables.

So in the example, the function counter sets the variable value to 0 then calls increment. increment stores value in its handle, so each time increment is called, value is incremented and overrides the first definition of value=0.

As a result, the output is 0 plus the number of times increment is called, which is each time a given instance of counter is called.

When you write this:

f1 = counter();
f2 = counter();

You create two separate instances of the function counter which will increment independently.

Cape Code
  • 3,584
  • 3
  • 24
  • 45