Home > Blockchain >  MATLAB parentheses upon object created inside of class calls class constructor
MATLAB parentheses upon object created inside of class calls class constructor

Time:09-01

classdef Dog < handle
    properties
        data;
    end

    methods
        function self = Dog(varargin)
            disp("Dog()")
        end

        function out = new(~)
            out = Dog();
            out('bark') = 1;
        end
    end
end

d=Dog(); why does d.new() print below?

Dog()
Dog()
Dog()

It also bypasses subsref if I overload it. Entering d in console gives

ans = 

  1×114 Dog array with properties:

    data

and isn't reproduced with d('bark') = 1.

The behavior changes if I get rid of varargin, instead there's an error. Also why 1x114?

CodePudding user response:

Here is what's happening when calling d.new() (after d = Dog()):

  1. out = Dog(); is invoked. This constructor call triggers the first output of "Dog()"
  2. out('bark') = 1; is invoked, which triggers the following:
    • The characters of 'bark' are interpreted as values [98 97 114 107 ]. Consequently, Matlab resizes out to a size of 114.
    • To construct a Dog object to fill positions [98 97 114 107 ] in out, Matlab calls the constructor again, this time with the input argument varargin equal to { 1 }. This triggers the second output of "Dog()".
    • To construct a Dog object to fill the other positions in out, Matlab calls the constructor again, this time with no input argument. This triggers the third output of "Dog()".

Furthermore, subsref is not bypassed, but simply not called, as you do not refer to the object in a reading manner.

And when you remove varargin, you get the error, because the constructor cannot be called anymore with one input argument, as explained in the second bullet point under 2. above.

CodePudding user response:

As I understand it, within class methods, indexing expressions always use the built-in subsasgn and subsref, not the overloaded (customized) one you might write yourself. This is so that overloading these functions doesn't remove the ability of class methods to access object properties.

So, within your class method, out(i) accesses the ith object in the array out. This is not out.data(i), out is really an array of objects of class Dog. Dog() creates a 1x1 array, which you would normally think of as an object, but it really is an array. Everything in MATLAB is an array!

Now for out('bark') = 1. 'bark', as explained by user16372530's anwser, is a 4-element array, with numeric values [98 97 114 107]. Thus out, which starts off as a 1x1 array of your custom class, is resized to an array of 114 elements, and to 4 of those elements you assign 1. Here, MATLAB needs to create an empty element to fill out the 113 new elements, so calls Dog() once and copies the result to each of those elements. Then it needs to convert 1 to your class, so calls Dog(1) to do so, and copies to result to the 4 indexed elements. Actually, as indicated by user16372530 in a comment below, first 1 is converted and then the empty object is created.

If you want your class method to use the overloaded indexing operator, you need to explicitly call subsasgn or subsref, which is ugly and hard to read. There really is no way, as far as I understand it, to use class objects inside the class methods as you actually intend your class to be used. The same code behaves differently inside a class method and outside of it.

MATLAB OOP has some really interesting features, but it also has a lot of weird and inconvenient things. I guess they did their best designing a custom class system within the previously existing MATLAB array syntax.

  • Related