Why does subclassing a numeric type break its use as a property of a custom class?

2 views (last 30 days)
I’m seeing some odd behavior while trying to use a subclassed numeric type in a custom class I’m creating. Within the custom class, if I specify a property as a vector of type double, I can specify a default value as a scalar and everything works as expected (it fills the vector with copies of the scalar value if I don’t provide an input). But as soon as I change the type to a subclass of double, such as the ExtendDouble example given in the documentation here, I can no longer use a scalar as the default value, even though the error message itself says I should be able to:
>> testClass([1;2;3])
Error setting default value of property 'param1' of class 'testClass':
Size of default value must match specified dimensions 3×1 or be scalar.
So I have two questions:
1. Why does my code work for double but not ExtendDouble?
2. Why is it even trying to use the default value at all, when I’ve explicitly provided the value as an input argument to the constructor?
My custom class code is as follows:
classdef testClass
properties
param1(3,1) ExtendDouble = 0
end
methods
function self = testClass(param1)
if nargin > 0
self.param1 = param1;
end
end
end
end

Accepted Answer

Matt J
Matt J on 2 Mar 2021
Edited: Matt J on 3 Mar 2021
1. Why does my code work for double but not ExtendDouble?
The ExtendDouble example is old. It's subsasgn() method was not written to properly handle the newer property initialization features. The following modification will fix the issue.
case '()'
newd = subsasgn(double(obj),s(1),double(b));
if isa(b,'ExtendDouble'),
obj = ExtendDouble(newd,b.DataString);
elseif isa(obj,'ExtendDouble')
obj= ExtendDouble(newd,obj.DataString);
end
2. Why is it even trying to use the default value at all, when I’ve explicitly provided the value as an input argument to the constructor?
Constructor functions have special behavior. Within them, an initial version of the output object "self" gets created with default values as soon as the constructor workspace is entered. Therefore, anything you do to self in the body of the testClass() constructor is simply modifying that initial object. It doesn't create it from scratch.
As a simple way to see this, you can test the following simpler class,
classdef myclass
methods
function self = myclass()
disp ' '
whos
end
end
end
Running the constructor shows that self has been created in its workspace, even though I did nothing to put it there:
>> obj=myclass;
Name Size Bytes Class Attributes
self 1x1 0 myclass
  7 Comments
David Sempsrott
David Sempsrott on 5 Mar 2021
Edited: David Sempsrott on 5 Mar 2021
The object isn’t visible if you call the constructor without passing any input arguments to it. But if you do pass an argument, the superclass object (which I’m calling the “precursor” object) is visible. See the following, where the whos command is placed just inside the constructor entrance as you did in your previous example:
>> ExtendDouble;
>> ExtendDouble(1);
Name Size Bytes Class Attributes
data 1x1 8 double
Notice the object created is a double not an ExtendDouble (i.e. it was created by the superclass constructor).
Matt J
Matt J on 6 Mar 2021
Edited: Matt J on 6 Mar 2021
The whos output that you have posted does not show the superclass object. That is the input argument "data" that you have passed to the constructor.

Sign in to comment.

More Answers (0)

Categories

Find more on Construct and Work with Object Arrays in Help Center and File Exchange

Products


Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!