4

Is it possible to define a MATLAB class such that the objects from this class can be called like any other function?

IOW, I'm asking whether one can write in MATLAB the equivalent of something like the following Python class:

# define the class FxnClass
class FxnClass(object):
    def __init__(self, template):
        self.template = template

    def __call__(self, x, y, z):
        print self.template % locals()

# create an instance of FxnClass
f = FxnClass('x is %(x)r; y is %(y)r; z is %(z)r')

# call the instance of FxnClass
f(3, 'two', False)

...
[OUTPUT]
x is 3; y is 'two'; z is False

Thanks!

Frank
  • 2,738
  • 19
  • 30
kjo
  • 33,683
  • 52
  • 148
  • 265

4 Answers4

5

I do not know, whether MATLAB directly supports what you want, but MATLAB does support first-class functions; closures might therefore provide a useable substitute, for instance:

function f = count_call(msg)
    calls = 0;

    function current_count()
        disp(strcat(msg, num2str(calls)));
        calls = calls + 1;
    end

    f = @current_count;
end

In this case, current_count closes over calls (and msg). That way you can express functions that depend on some internal state. You would use it this way:

g = count_call('number of calls: ') % returns a new function ("__init__")
g()                                 % "__call__"
Frank
  • 2,738
  • 19
  • 30
4

I will be interested to see if this is possible without simply creating a java method in Matlab. I know you can do the following

classdef ExampleObject
    properties
        test;
    end
    methods
        function exampleObject = ExampleObject(inputTest)
            exampleObject.test=inputTest;
        end
        function f(exampleObject,funcInput)
            disp(funcInput+exampleObject.test);
        end
    end
end

>> e=ExampleObject(5);
>> f(e,10)
    15

But as far as my knowledge goes, if you tried to override the call function you'd run into a conflict with Matlab's parenthetical subscript reference subsref. You can find a reference here showing how to overwrite that, and you might be able to get it to do what you want...but it doesn't seem like good form to do so. Not sure how Matlab would handle a call to an object (as opposed to a function) without it getting confused with this.

Salain
  • 752
  • 6
  • 14
4

One way is to override the feval function for your class:

classdef FxnClass < handle
    properties
        template
    end
    methods
        function obj = FxnClass(t)
            obj.template = t;
        end

        function out = feval(obj, varargin)
            out = sprintf(obj.template, varargin{:});
        end
    end
end

This would be used as:

>> f = FxnClass('x = %f, y = %s, z = %d');
>> feval(f, 3,'two',false)
ans =
x = 3.000000, y = two, z = 0

Now if you want to provide additional syntactic sugar, you could redefine the subsref function for your class as @Salain suggested. Add the following to the previous class definition:

classdef FxnClass < handle
    ...

    methods
        function out = subsref(obj, S)
            switch S(1).type
                case '.'
                    % call builtin subsref, so we dont break the dot notation
                    out = builtin('subsref', obj, S);
                case '()'
                    out = feval(obj, S.subs{:});
                case '{}'
                    error('Not a supported subscripted reference');
            end
        end
    end
end

Now you could simply write:

>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3,'two',false)
ans =
x = 3.000000, y = two, z = 0

Personally I don't particularly like overriding the subsref or subsasgn functions. They are used for too many cases, and its sometimes hard to get them write. For example all the following will eventually call the subsref method with different input:

f(..)
f.template
f.template(..)
f(..).template
f(..).template(..)

There is also the case of the end keyword which could appear in indexing, so you might have to also override it as well in some cases. Not to mention that objects can also be concatenated into arrays, which makes things even more complicated:

>> ff = [f,f];
>> ff(1)        % not what you expect!

That said, I think @Frank's suggestion to use nested functions with closures is more elegant in this case:

function f = FxnClass(t)
    f = @call;
    function out = call(varargin)
        out = sprintf(t, varargin{:});
    end
end

which is called as before:

>> f = FxnClass('x = %f, y = %s, z = %d');
>> f(3, 'two', false)
Community
  • 1
  • 1
Amro
  • 123,847
  • 25
  • 243
  • 454
  • This is probably too much to ask for, but suppose your call had two args "x", "y", would it be possible to get MATLAB to predict the signature as you're trying in "f(" ? – Derek Jul 26 '15 at 18:11
  • @Derek I'm not sure I understand your question.. What do you mean by predict the signature? – Amro Jul 26 '15 at 23:54
1

If you mean that you want a class to hold a method which you use like a normal function (eg. defined in an m-file), then yes, Matlab does support static methods.

A static method runs independently of any instances of that class, in fact, you don't even need to instantiate a class to use its static methods.

Matlab does not support static fields, however, so you would have to instantiate such a class first, and then set its fields before using the functions (which presumably make use of these fields, since you are asking this question).

Given the limitation with static members, you might be better off with closures, as described by Frank.

Community
  • 1
  • 1
Superbest
  • 25,318
  • 14
  • 62
  • 134
  • No, kjo wants to treat an object is if it were a function. – Frank Aug 31 '12 at 23:17
  • @Frank I don't really understand this. To what end? So that he can control the currying of the class's methods? That can be done by passing values to the constructor, which sets fields, and then calling functions as usual. So that he can give a new to the constructor call? That can be done by making an anonymous function which calls the constructor. Not arguing with the question, just curious. – Superbest Aug 31 '12 at 23:25
  • As I understand it, kjo essentially wants to achieve some form of partial application. Yes, technically you don't need closures if you have objects (and vice versa). – Frank Aug 31 '12 at 23:34
  • @Frank so how about just making a function, which takes a parameter, curries another function using that parameter, and then returns a handle to the curried function? Ie. `make_power = @(base)( @(x) power(base, x) )` (taken from http://stackoverflow.com/questions/9154271/partial-function-evaluation-in-matlab) – Superbest Aug 31 '12 at 23:44
  • Well, that _is_ a closure; in fact, it is functionally equivalent to my proposed solution. – Frank Sep 01 '12 at 00:09
  • @Frank, oh, that's pretty much exactly what you said in your answer. Sorry, I should have read it more carefully! – Superbest Sep 01 '12 at 00:16