MATLAB Answers

How to pass a method as a function handle

77 views (last 30 days)
Ok, so I have an object as a property of a class. This object has methods. I need to use an object's method as a handle, like follows:
classdef MyClass
properties
my_obj_with_methods
end
methods
function r = foo(obj, func, a, b)
r = func(a, b);
end
function r = bar(obj)
r = obj.foo(@obj.my_obj_with_methods.my_method, 1, 2);
end
function r = foobar(obj)
r = obj.foo(@obj.my_obj_with_methods.my_other_method, 1, 2);
end
end
end
When I try to do this, I get:
"Undefined function or variable 'obj.my_obj_with_methods.my_method"
1 - I know I can solve this with an `if/else`, but I thought "hey, Matlab is a functional language, I could use those great functional features!"
2 - I'm not complicating things, I have good reason to want to do this
Thanks!

Accepted Answer

Richard Brown
Richard Brown on 7 Nov 2019
I think the issue is that to use the @ construction, the thing you're applying it to needs to be named function in scope. There is no function "called" obj.my_obj_with_methods.my_method, that construction accesses the method another way.
so you can use the following piece of delight which does work, but is as ugly as sin:
classdef MyClass
properties
my_obj_with_methods
end
methods
function r = foo(obj, func, a, b)
r = func(a, b);
end
function r = bar(obj)
r = obj.foo(@(varargin) obj.my_obj_with_methods.my_method(varargin{:}), 1, 2);
end
function r = foobar(obj)
r = obj.foo(@(varargin) obj.my_obj_with_methods.my_other_method(varargin{:}), 1, 2);
end
end
end
Or ... use python (**ducks**)
  1 Comment
Lucas Abbade
Lucas Abbade on 8 Nov 2019
It might be ugly but it worked as I intended, so that's good enough for me, thanks!

Sign in to comment.

More Answers (2)

Guillaume
Guillaume on 7 Nov 2019
Can't tell you why it doesn't work as you have written, I suspect that this has to do with how the . operator is implemented in matlab. It may be worth raising a service request with Mathworks to get a full explanation.
It's easily worked around though. You have to remember that obj.method(arg1, arg2, ...) is the same as method(obj, arg1, arg2, ...), so:
classdef MyClass
properties
my_obj_with_methods
end
methods
function r = foo(obj, func, subobj, a, b) %method should be static since it doesn't use obj
r = func(subobj, a, b);
end
function r = bar(obj)
r = obj.foo(@my_method, obj.my_obj_with_methods, 1, 2);
end
function r = foobar(obj)
r = obj.foo(@my_other_method, obj.my_obj_with_methods, 1, 2);
end
end
end
Of course, in this simple example, a better solution would be:
classdef MyClass
properties
my_obj_with_methods
end
methods
function r = foo(obj, func, a, b) %method can no longer be static
r = func(obj.subobj, a, b);
end
function r = bar(obj)
r = obj.foo(@my_method, 1, 2);
end
function r = foobar(obj)
r = obj.foo(@my_other_method, 1, 2);
end
end
end
  1 Comment
Lucas Abbade
Lucas Abbade on 8 Nov 2019
Thanks for the explanation, unfortunately, I don't this will solve my problem because `my_obj_with_methods` is actually a Python object, I'll try it out anyway

Sign in to comment.


Steven Lord
Steven Lord on 7 Nov 2019
Are my_method and my_other_method Static or non-Static methods of the class of the value stored in the my_obj_with_methods property of your object? Let's take a simple little class with a constructor, one Static method, and one non-Static method.
classdef example489847
properties
x
end
methods
function obj = example489847(xin)
obj.x = xin;
end
function q = twoTimes(obj)
q = 2*obj.x;
end
end
methods(Static)
function whatAmI
disp('I am an example489847');
end
end
end
I can make a handle to twoTimes.
>> fh = @twoTimes;
This function handle fh has no knowledge of the example489847 class. If I call this function handle with an instance of this class as input, then MATLAB will determine that it should call the twoTimes method of the example489847 class. But if you were to call it with other data, like a normal double array, MATLAB doesn't know of a twoTimes function that accepts a double so it throws an error. If there was another class with a twoTimes method, I could call the function handle with an instance of that class and have its twoTimes method run.
>> obj = example489847(42);
>> y = fh(obj)
y =
84
>> fh(42)
Undefined function 'twoTimes' for input arguments of type 'double'.
To make a function handle to a Static function, you need its "full name".
>> fh2 = @example489847.whatAmI;
>> fh2()
I am an example489847
>>
This is just like how you would call it if you wanted it to execute immediately.
>> example489847.whatAmI()
I am an example489847
>>
  4 Comments
Guillaume
Guillaume on 8 Nov 2019
Steven, it's actually a bit more murky than that. You can create function handle to method class using the syntax:
@obj.method
we do that frequently in App designer, for example when defining callbacks.
And that works also with my demo class above. Interestingly, something I hadn't noticed before, matlab does a bit of magic here:
>> mc = MethodClass; %class defined in previous comment
>> fh = @mc.foo; %function handle to class method
>> fh(1) %no problem calling the method
ans =
2
>> fh
fh =
function_handle with value:
@(varagin)mc.foo(varargin{:})
So, matlab has rewritten the function handle a bit!
However, add an extra level of indirection with an additional dot in the expression:
>> mystruct.mc = MethodClass;
>> fh = @mystruct.mc.foo;
>> fh(1)
Unrecognised function or variable 'mystruct.mc.foo'
>> fh %no more magic :(
fh =
function_handle with value:
@mystruct.mc.foo
Basically, we can't chain two subsref calls when creating a function handle but the parser will let it through when it's two dot calls and the error is caught at runtime, whereas with {} and () it's caught at parse time:
>> fh = @mystruct.mc.foo; %parser is fine. Runtime error when called
>> mycell{1} = mc;
>> fh = mycell{1}.foo; %parser error
Error: Invalid expression...
>> mc(2) = MethodClass;
>> fh = mc(1).foo; %parser error
Error: Invalid expression...

Sign in to comment.

Products


Release

R2018a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by