New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Constructor inheritance #9468
Comments
Removed Type-Defect label. |
This could work: If you extend a class and specify no constructors, you currently get a default constructor "myClass(): super();". class C {
C.foo();
}
class D extends C {} // no constructor inherited, and it's an error.
class E {}
class F = C with E; // inherited constructor! It would be consistent to make the constructors inherit everywhere. It should not be a breaking change (but maybe an inconvenient one), since any class that currently gets a default constructor added will have a superclass with a unnamed zero-argument constructor, and so it will still get the same constructor. It might inherit more constructors too, which is the inconvenient part. |
This comment was originally written by ras...@mindplay.dk For the record, I also have a long history with PHP, as well as many other languages. From my perspective, explicit constructors do not violate the DRY principle, because you're not simply repeating yourself. The constructor in a base-class defines the needs of the base-class. A similar constructor in a sub-class defines the needs of the sub-class, which aren't automatically the same as those of the base-class - to assume so, is to assume that the author of the base-class can predict the future, which may be the case in a closed system, but in the case of open systems (such as frameworks) you can't make those assumptions. I wrote a bit of a dissertation on the same subject on stackoverflow: http://stackoverflow.com/questions/15665354/why-dart-does-not-inherit-constructor/17472936#17472936 |
Much could be said about the disadvantages of constructors, and in fact I have: http://gbracha.blogspot.com/2007/06/constructors-considered-harmful.html Dart constructors solve some but not all of the issues. Constructors must deal with the task of initializing the instance, and thus are specialized in subclasses. In general, it is not valid to inherit a constructor, as it will not properly initialize the subclass. So you should not have constructor inheritance by default. In languages where class methods act as constructors (like Ruby) you get inheritance by default, and it is often a problem because you can instantiate a class and not initialize it probably. In those cases where the a subclass requires no further initialization, and no change to the incoming parameters, it would be convenient to not have to introduce special constructors. In some cases, this actually works (if you only use default constructors). Those situations where you really have to define fairly pointless constructors to forward the constructor calls to the superclass are the minority. For those cases, one could imagine a sugar saying you want to inherit the constructors from the superclass. You'd have to state that, and it would only be worthwhile if it were substantially shorter than the new constructors. It seems an exceeding amount of sugar to me, and I would not expect it any time soon. |
The parent does not know about the child but wise versa. Therefore the child is also responsible for initializing itself and the parent correctly. The parent constructor works in itself and describes its parameters in its signature. If the child fails to pass the required arguments its the childs fault. Constructors are specialized in nothing but the class that they belong to. What is the opposite of a "specialized" constructor? A "generalized" constructor? This doesnt make sense.
No they are not. Basically you have to to this in every class you extend which accepts constructor arguments. I had multiple occurences where I did not want to use inhertance because I have to copy all the parameter lists for constructors just to override a method.
Why do I dont want to inherit the constructor? Here is a usecase: class ListBloc<T> {
final ListRepositoryInterface repository;
compareItems(T element) => element == item;
ListBloc(@required this.repository);
}
class EntityListBloc extends ListBloc<Entity> {
/// Here if have to copy/paste the complete constructor for no reason because if not I cant pass [repository]
EntityListBloc(@required ListRepositoryInterface repository): super(repository);
compareItem(Entity element) => this.item.id == element.id;
} I also have PHP experience so heres an working example: class Superclass {
protected $prop;
public function __construct($prop) {
$this->prop = $prop;
}
public function printProp() {
echo $prop;
}
}
/**
* Override method, constructor is inherited
*/
class FirstChild extends Superclass {
printProp() {
echo "Hello: $prop";
}
}
/**
* Override constructor
*/
class SecondChild extends Superclass {
public function __construct($prop) {
// Do stuff
parent::__construct($prop);
}
}
$super = new Superclass("World");
$child1 = new FirstChild("World");
$child2 = new SecondChild("World");
$super->printProp(); // World
$child1->printProp(); // Hello: World
$child2->printProp(); // World I cannot really understand the disadvantages of constructor inheritance. EDIT: abstract class EntityEvent {
final Entity entity;
EntityEvent(this.entity);
}
class EntityCreatedEvent extends EntityEvent {
EntityCreatedEvent(Entity entity): super(entity);
}
class EntityViewedEvent extends EntityEvent {
EntityViewedEvent(Entity entity): super(entity);
}
class EntityUpdatedEvent extends EntityEvent {
EntityUpdatedEvent(Entity entity): super(entity);
} This could be written like the following: abstract class EntityEvent {
final Entity entity;
EntityEvent(this.entity);
}
class EntityCreatedEvent extends EntityEvent { }
class EntityViewedEvent extends EntityEvent { }
class EntityUpdatedEvent extends EntityEvent { } |
Agree. This is utterly insane. There should be a way to override constructors (at least) and inherit the list of parameters. If you are extending a class, by default it implies that you will be reusing those same params. |
Just as an example, working in a tween lib right now, and every single sub-class needs this boilerplate: class Move extends Tween<Offset> {
const Move({required Offset from, required Offset to, Curve? curve})
: super(from: from, to: to, curve: curve); Which ends up being about 50% of the body of the class. Where base class should really be handling it already for most tweens w/ abstract class Tween<T> {
const Tween({required this.from, required this.to, this.curve});
final T from;
final T to;
final Curve? curve; It would be really nice if we could optionally change some defaults, but still inherit the overall signature somehow, as that is a common use case. Another issue with duplicating params, is you often have to duplicate the default values. This is definitely not dry. A good use case for this is Instead of this: class MinSizeRow extends Row {
MinSizeRow({
Key? key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.min, // <!----- only change we want to make
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection? textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline? textBaseline,
List<Widget> children = const <Widget>[],
}) : super(
children: children,
key: key,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection,
verticalDirection: verticalDirection,
textBaseline: textBaseline,
);
} Would be really nice if we could instead write something closer to: class MinSizeRow extends Row {
MinSizeRow(inherited) : super(this.mainAxisSize = MainAxisSize.min);
} |
There is a new language feature coming up (probably 2.17, no promises) known as super parameters, and it will allow you to do it in the following way: class MinSizeRow extends Row {
MinSizeRow({
super.key,
super.mainAxisAlignment,
super.mainAxisSize = MainAxisSize.min, // Default value can be included, useful if different from super.
super.crossAxisAlignment,
super.textDirection,
super.verticalDirection,
super.textBaseline,
super.children,
});
} It isn't entirely as concise as |
Nice, ty! |
Seems like a neat workaround but still requires to copy the constructor. |
This issue was originally filed by efesak...@gmail.com
Hi,
i am coming from PHP world and i am curious why developers choose the way not adding constructor (with arg) to inheritance. From my view it violates DRY principle by repeating code. I did little research - PHP, Ruby, Python inherits constructor. Java, C#, C++ not. C++0x has new feature - method explicitly defining constructor inherition.
Is there any reason or advantage for programmer not having constructor inherited?
(i am not experienced dart nor java programmer, but this makes me no sense in modern language)
The text was updated successfully, but these errors were encountered: