Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matlab OOP - Overloading size()

I want to overload the size() function for one of my classes so that it doesn't return the object's size but rather the size of a specific member. The problem is that Matlab calls obj.size in the class constructor in order to determine the object array size.

For example:

classdef dataClass < handle

properties
    memberVar
end

methods 
    function obj = dataClass(mvIn)
        if nargin ~= 0
            if ~ismatrix(mvIn)
                error('Input must be a matrix');
            end

            obj.memberVar = mvIn;
        end
    end

    function sz = size(obj, varargin)
        h = @(x)builtin('size', x, varargin{:});
        sz = cell2mat(cellfun(h, {obj.memberVar}', 'uni', 0));
    end       
end

end

does not work because the size of the object array is made the same size as memberVar

a = dataClass(ones(100))

a = 

  100x100 dataClass array with properties:

  memberVar: [100x100 double]

A workaround is to implement the overload as

function sz = size(obj, varargin)
    idx = strcmpi(varargin, 'mv');
    if any(idx)
        varargin = varargin(~idx);
        h = @(x)builtin('size', x, varargin{:});
        sz = cell2mat(cellfun(h, {obj.memberVar}', 'uni', 0));
    else
        sz = builtin('size', obj, varargin{:});
    end
end 

and call size(obj, 'mv') but that defeats the whole purpose of the overload, because I want to call size() as I would for any other object.

Any suggestions?

like image 574
phausamann Avatar asked Sep 04 '26 12:09

phausamann


1 Answers

You need to be extremely careful if you want to overload size for a class - that's careful both in how you implement things, and careful in your design of exactly how you want the class to behave.

First, note that there's a decision to be made in whether you would like to be able to make arrays of your dataClass objects, or whether you are OK with only ever making scalar dataClass objects. If you want to be able to make arrays of dataClass objects, what exactly do you want size to do when given such an array? Do you want it to report the size of the array, or the size of the data within one dataClass? Which dataClass? Do you want it to switch behaviours when it is called on a scalar and on an array? That's going to get confusing fast.

So first of all, I would suggest that if you want to overload size, you'll probably want to restrict your class so that it's not possible to work with anything other than scalars. You can do this by overloading cat, horzcat and vertcat, and having them error (carefully, under exactly the right circumstances).

In addition to that, you need to be careful to ensure that you overload not only size, but also numel. size and numel interact in some non-obvious ways.

So with that said, you should be able to implement something like this:

classdef dataClass < handle

properties
    memberVar
end

methods 
    function obj = dataClass(mvIn)
        if nargin ~= 0
            if ~ismatrix(mvIn)
                error('Input must be a matrix');
            end

            obj.memberVar = mvIn;
        end
    end

    function sz = size(obj, varargin)
        sz = builtin('size', obj.memberVar, varargin{:});
    end       
end

end

If you also overloaded cat, horzcat, vertcat and numel as suggested above, I think this does what you're asking for.

However, there's another thing to be careful of. You mention that MATLAB calls size in the object constructor to determine its size. That's not actually the case - what is happening is that after you construct it, MATLAB displays the result at the command line and to do so calls disp, which then calls size to determine the size. It reports it as a 100x100 array of dataClass, which is not the case - it's a 1x1 array with a 100x100 memberVar. You can test this by trying to access a(2), which will error.

So you also then need to overload the display methods for the class. You can do this either by inheriting your class from matlab.mixin.CustomDisplay, or by directly overloading the methods disp and/or display. Make them display whatever you want, such as the contents of memberVar.

Note one last thing: in the Workspace Browser, a is reported as being 100x100 - this is again the output of size. I hope you're OK with that, as there's no way I know of to have size report one thing to the command line and another to the Workspace Browser.

I hope that helps - as you can see, there's a lot to think about when overloading size, which is why it's not typically recommended.

like image 74
Sam Roberts Avatar answered Sep 07 '26 04:09

Sam Roberts