Reputation: 11
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
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