Why do I get an error if do not define a constructor in the inherited class?

Here's a simple example that does not work in the MATLAB language:
classdef Bar < handle
% Bar class
properties
Value
end
methods
function self = Bar(value)
self.Value = value;
end
end
end
classdef Foo < Bar
% Foo class
% No has constructor. We want to use the "Bar" constructor
end
>> f = Foo(10)
Error using Foo
Too many input arguments.
Too many input arguments.???
Ok...
>> f = Foo()
Error using Bar (line 10)
Not enough input arguments.
Error in Foo (line 1)
classdef Foo < Bar
What's going on? This is the ordinary inheritance. I would not want every time to write this:
classdef Foo < Bar
methods
function self = Foo(value)
self = self@Bar(value);
end
end
end

3 comentarios

It's not a defect of language design, it's a feature? :)
This seems to be version specific. I'm hopping beween versions right now and 2016b throws the same error but 2019a doesn't ...

Iniciar sesión para comentar.

 Respuesta aceptada

Daniel Shub
Daniel Shub el 25 de En. de 2013
Editada: Daniel Shub el 25 de En. de 2013
Classes and subclasses do not need a constructor.
classdef mysimpleclass
end
is perfectly valid. If a subclass does not have a constructor it calls the superclass constructor with no arguments. In other words the default constructor looks something like
function obj = mysubclass()
obj = obj@myclass;
end
It sounds like you would like the default constructor to look like
function obj = mysubclass(varargin)
obj = obj@myclass(varargin{:});
end
such that it would pass the arguments up the chain. I think both are reasonable defaults. There is a slight difference between MATLAB and Python (and most other languages) which potentially swayed TMW to go with the former approach in which no arguments get passed to the superclass. Because everything is an array in MATLAB, and how TMW chose to implement the OO system, the constructor for every MATLAB class needs to support being called with no input arguments (this is well documented).
EDIT
I think the choice becomes clearer if expand from the no constructor case a little bit. Consider
classdef mysubclass < myclass
methods
function obj = mysubclass(varargin)
end
end
end
Calling the mysubclass constructor invisibly calls the myclass constructor with no arguments. I believe this is documented. As we are guaranteed that the myclass constructor can be called with no arguments, it makes a little more sense to pass it no arguments (which will not crash) than pass it all the arguments which might result in an error. Either way you will end up with having to explicitly call the superclass constructor sometimes (either to pass all arguments or to pass no/some arguments). Passing all arguments seems less robust than pass no arguments. Passing a subset just seems silly.

5 comentarios

Matt J
Matt J el 25 de En. de 2013
Editada: Matt J el 25 de En. de 2013
I'm not sure I see the contradiction. The alternative default constructor
function obj = mysubclass(varargin)
obj = obj@myclass(varargin{:});
end
could still support the no argument case. If no arguments were given, the above would act with varargin={}
@Matt j see my edit.
@Daniel
> Passing a subset just seems silly
I agree.
> ...the myclass constructor can be called with no arguments, it makes a lot more sense to pass it no arguments (which will not crash) than pass it all the arguments which might result in an error.
It is a disputed, that it is better... :)
@Evgeny, you are correct. I changed "a lot more sense" to "a little more sense". I don't think one is substantially better than another. Just as you don't want to write "self = self@Bar(value);" every time, TMW decided that they/we didn't want to write "self = self@Bar;" every time. You asked "What's going on?" and I tried to explain what is going on and that it essentially was a design decision by the TMW.
Evgeny Pr
Evgeny Pr el 25 de En. de 2013
Editada: Evgeny Pr el 25 de En. de 2013
@Daniel
Thanks for your reasonable answer. I will choose your answer as an accepted.
@Matt J
Thanks for the discussion!

Iniciar sesión para comentar.

Más respuestas (1)

Matt J
Matt J el 24 de En. de 2013
Editada: Matt J el 24 de En. de 2013
Write the Bar constructor to handle the case when no input arguments are passed. Otherwise, it needs to get those arguments from somewhere, e.g.,
function self = Bar(varargin)
if nargin
value=varargin{1};
else
value=somedefault;
end
self.Value = value;
end

17 comentarios

classdef Bar < handle
% Bar class
properties
Value
end
methods
function self = Bar(value)
if nargin
self.Value = value;
else
self.Value = pi;
end
end
end
end
Seems to work
There is an explanation of why it was done? For example, Python language supports this case.
I'm developing a the library in which a exist base classes, and users can create their own inherited classes. The constructor of the base class implements the necessary logic, it is not needed in a inherited class without the need. It's strange that I can't do this in matlab. Do not define a constructor each time:
function self = UserClass(value)
self = self@BaseClass(value);
end
Simple example with GUI Conception:
% Base GUI Widget class
classdef BaseWidgetUi < handle
properties
hParent
end
methods
function self = BaseWidgetUi(hParent)
if nargin < 1
self.hParent = gcf;
else
self.hParent = hParent
end
self.createUi();
self.setupUi();
end
end
methods (Abstract, Access = protected)
createUi(self);
setupUi(self);
end
end
% User class implements GUI Widget
classdef UserWidgetUi < BaseWidgetUi
% The constructor is not needed, but parent must set
methods (Access = protected)
function createUi(self)
% ...
end
function setupUi(self)
% ...
end
end
end
Matt J
Matt J el 24 de En. de 2013
Editada: Matt J el 24 de En. de 2013
It's strange that I can't do this in matlab. Do not define a constructor each time:
You don't have to define a base class constructor in MATLAB. It can always default to an internal constructor. Even if you do define an explicit base class constructor, you do not have to pass arguments to it from the subclass constructor as long as the base constructor can handle the no-argument case. From the OOP doc:
if the class being created is a subclass, MATLAB calls the constructor of each superclass class to initialize the object. Implicit calls to the superclass constructor are made with no arguments. If superclass constructors require arguments, you must call them from the subclass constructor explicitly.
Ok. I already read it in the documentation.
But, do not you think that this artificial limitation of language design?
What limitation are you talking about? The message I've been trying to convey to you is that you are not required to do anything.
I need to define a superclass constructor. And every time I have to write a constructor in a subclasses for my case, even if it does nothing (only transfers arguments to superclass). :)
function self = UserClass(value)
self = self@BaseClass(value);
end
I'm not sure why you think you have to. Below is an example of a base class (myclass) which defines a constructor, but the subclass (mysubclass) does not. I can construct an instance of the subclass no problem
>> obj=mysubclass
obj =
mysubclass
Properties:
value: 0
Methods, Superclasses
###################
classdef myclass
properties
value;
end
methods
function obj=myclass(value)
if nargin
v=value;
else
v=0;
end
obj.value=v;
end
end
end
###############
classdef mysubclass < myclass
end
This works if you do not specify an argument in the constructor to create a subclass instance. But I need to set it in the constructor of subclass.
>> obj=mysubclass(10)
Error using mysubclass
Too many input arguments.
Too many input arguments. Here's the problem!
###############
classdef mysubclass < myclass
methods
function obj=mysubclass(value)
if nargin < 1
value = 10;
end
obj = obj@myclass(value)
end
end
end
############
>> obj=mysubclass(10)
obj =
mysubclass handle
Properties:
value: 10
Methods, Events, Superclasses
For example, the code in Python language is predictable:
class Bar(object):
def __init__(self, value=0):
self.value = value
class Foo(Bar):
pass
>> f = Foo()
>> print f.value # disp 0
>> f = Foo(10)
>> print f.value # disp 10
And this is not a limitation in MATLAB OOP design?
Matt J
Matt J el 25 de En. de 2013
Editada: Matt J el 25 de En. de 2013
I'm not familiar enough with Python to understand your example fully, but in any OOP design, I think, you need some way for a subclass constructor to distinguish between which of its constructor parameters go to the base class part of the object and which of its parameters are needed by the subclass part.
Apparently, the 'pass' command you issue is a way of saying "send all parameters to the base class"? If so, it seems like it plays an equivalent role to
self = self@BaseClass(...);
and I don't really see the big difference.
'pass' - do nothing
>> but in any OOP design, I think, you need some way for a subclass constructor to distinguish between which of its constructor parameters
Yes, I agree. For example in Python it is:
class Foo(Bar):
def __init__(self, value=0):
# Foo Constructor
# Call Bar constructor
super(Foo, self).__init__(value)
# do something
But you can do without it, if it does not have to explicitly. In MATLAB as it is compulsory.
Well, then you're saying MATLAB should assume all parameters are to be fed to the base constructor unless told differently? That might make sense if you believe the subclass and base class will often require identical parameters. I don't know if that's likely for everybody...
Evgeny Pr
Evgeny Pr el 25 de En. de 2013
Editada: Evgeny Pr el 25 de En. de 2013
Yes, that's right! I want matlab transfers to the constructor of the superclass all parameters, unless the subclass constructor is not define. And I not see difficulties in implementing such behavior. This is useful, see my example with GUI Conception (third comment).
All the time? But there will be cases where some parameters are required by the subclass only.
Then you will need to write a constructor in a subclass. But it is even less often (in my experience) :)
Matt J
Matt J el 25 de En. de 2013
Editada: Matt J el 25 de En. de 2013
Then you should correct what you said here
I want matlab transfers to the constructor of the superclass all parameters, unless the subclass constructor is not define.
You really meant to say "I want matlab to transfer to the constructor of the superclass all parameters, IF the subclass constructor is not defined."
Yes, I think I can see what you mean. Although, it somehow seems cleaner to me that for every function call
subclassConstructor(params)
there is a function signature to match. But that might just be the bias of my experience...
Yes, sorry. My english is bad. :(

Iniciar sesión para comentar.

Categorías

Más información sobre Construct and Work with Object Arrays en Centro de ayuda y File Exchange.

Productos

Preguntada:

el 24 de En. de 2013

Comentada:

el 27 de Mayo de 2020

Community Treasure Hunt

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

Start Hunting!

Translated by