Frank
Frank

Reputation: 11

Function handle as a property of a class - Matlab

I define a class CellArrayHandle whose only property is a cell array of function handles:

classdef CellArrayHandle < handle    
    properties
        cel  % cell array of function handles    
    end 
end

Suppose myHandle is an object of CellArrayHandle, so myHandle.cel is a n-by-1 cell array of function handles, i.e myHandle.cel{i} is a function handle for i = 1 to n.

I want to do some update (for e.g. i=1), but the following does not work:

  myHandle.cel{1} = @(x) myHandle.cel{1}(x) + 0.5;

Matlab says "Maximum recursion limit of 500 reached", so it seems to be understood as an infinite recursion. However the fowllowing works:

  f = @(x) f(x) + 0.5;

for a function handle f.

It seems when I encapsulate a function handle into a class as a property, the above update method will not work.

I do not understand the difference between the former and the latter. Could any people help me on this point? Thank you very much.

Best regards,

Frank

Upvotes: 1

Views: 1396

Answers (1)

TroyHaskin
TroyHaskin

Reputation: 8401

The difference stems from the semantics of a handle class:

You can assign the handle object to multiple variables or pass it to functions without causing MATLAB to make a copy of the original object.

Or, to borrow the original idea of Highlander, when you instantiate a handle class, "there can be only one" (glob of the instance in memory which all variables you assign it to only creating references and not new copies).

Consider the example script:

f = @(x) x;
f = @(x) f(x) + 0.25;
f = @(x) f(x) + 0.50;

b = CellArrayHandle();
b.cel{1} = @(x) x;
b.cel{1} = @(x) b.cel{1}(x) + 0.25;
b.cel{1} = @(x) b.cel{1}(x) + 0.5;

fval = f(1);
bval = b.cel{1}(1);

If I debug this script and look at the stack right before fval evaluates, I see:

K>> dbstack
> In @(x)x
  In @(x)f(x)+0.25
  In @(x)f(x)+0.5

So Matlab was able to create a copy of the current f function handles during the creation of subsequent f handles and could form a stack.

When I do the same thing to b, I get this:

K>> dbstack
> In @(x)b.cel{1}(x)+0.5
  In @(x)b.cel{1}(x)+0.5
  In @(x)b.cel{1}(x)+0.5
  In @(x)b.cel{1}(x)+0.5
  In @(x)b.cel{1}(x)+0.5
  In @(x)b.cel{1}(x)+0.5
  ...

This happens because each assignment to a property of b makes the property of b that value without creating a new instance of the class. So the assignment is inherently infinitely recursive.

You can fix this by not having the class inherit from handle but from value (the default). By removing the < handle from the classdef, and repeating the dbstack of the handle call, we have

K>> dbstack
> In @(x)x
  In @(x)b.cel{1}(x)+0.25
  In @(x)b.cel{1}(x)+0.5

And this happens because each assignment to a property of b now makes a copy of the current b, instantiates a new b, and stores the old definition of b within the function handle to form the proper stack.

Upvotes: 2

Related Questions