4

In R2018b, I have the following setup:

classdef SomeClass < handle    
    methods
        function SomeMethod(obj)
            disp in!
        end
    end    
end

classdef SomeOtherClass < handle

    properties (Constant)
        instance = SomeClass()
    end

    methods
        function Test(obj)
            hdl = @obj.instance.SomeMethod;
            hdl();            
        end
    end

end

However, running the Test() method gives an error:

>> SomeOtherClass().Test() 
Undefined function or variable 'obj.instance.SomeMethod'.

Changing the Test() method to:

function Test(obj)
    A   = obj.instance;
    hdl = @A.SomeMethod;
    hdl();
end

gives the desired result:

>> SomeOtherClass().Test
in!

I'm puzzled...why do I need the middle man A?

Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
Rody Oldenhuis
  • 37,726
  • 7
  • 50
  • 96

2 Answers2

3

Following @gnovice's finding:

>> obj = struct('instance', SomeClass());
>> hdl = @obj.instance.SomeMethod
hdl =
  function_handle with value:
    @obj.instance.SomeMethod

>> hdl(obj.instance)
Undefined function or variable 'obj.instance.SomeMethod'.

>> hdl()
Undefined function or variable 'obj.instance.SomeMethod'.

But:

>> instance=SomeClass();
>> hdl = @instance.SomeMethod
hdl =
  function_handle with value:
    @(varargin)instance.SomeMethod(varargin{:})

>> hdl(instance)
Error using SomeClass/SomeMethod
Too many input arguments.

Error in @(varargin)instance.SomeMethod(varargin{:})

>> hdl()
in!

Note how the function handle created in this second case is actually an anonymous function, which includes the object in it. This is a special case of the @ operator, not the normal usage, which would be:

>> hdl=@SomeMethod
hdl =
  function_handle with value:
    @SomeMethod

>> hdl(instance)
in!

What this case actually does is create an anonymous function that embeds the object you intend to call this method on. You can create such a function this way:

>> hdl=@()obj.instance.SomeMethod()
hdl =
  function_handle with value:
    @()obj.instance.SomeMethod()

>> hdl()
in!
Cris Luengo
  • 55,762
  • 10
  • 62
  • 120
  • Great answer! Weird limitation though...doesn't make things more intuitive IMHO...Also you'd have to write the unwieldy `@(varargin)obj.instance.SomeMethod(varargin{:})` just to get some arguments in...which kind of forces you to use the middle man. Oh well, we're [used to that from MATLAB](https://stackoverflow.com/q/3627107/1085062) – Rody Oldenhuis Oct 17 '18 at 23:45
  • @Rody: you could consider submitting this as a bug to MahWorks. I agree that it makes little sense. – Cris Luengo Oct 18 '18 at 00:09
  • Yes, I guess I should. What version(s) did you try this on? – Rody Oldenhuis Oct 18 '18 at 00:48
  • @Rody: I used R2018b. – Cris Luengo Oct 18 '18 at 00:49
2

I don't have a complete answer yet, but here's some more food for thought: you can recreate the same result using a structure in place of SomeOtherClass:

>> obj = struct('instance', SomeClass());
>> hdl = @obj.instance.SomeMethod;
>> hdl()
Undefined function or variable 'obj.instance.SomeMethod'.

I'm leaning towards this being a limitation of how the function handle operator works as opposed to the MATLAB class system.

gnovice
  • 125,304
  • 15
  • 256
  • 359