Search code examples
matlaboopanonymous-functionhandle

Function handle to a method in a constant property


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?


Solution

  • 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!