On Sep 12, 2014, at 8:18 AM, Mark S. Miller wrote:
> Even when written explicitly, either by an IDE or a human, the
>
> constructor(a, b, c) {
> this = new super(...arguments);
> ...
> }
>
> pattern is usually bad. It is fine in a certain special case I mention below.
> It would be a disaster to have this pattern be the default smoothed over by a
> syntactic shortcut. Here's the problem:
>
> ----- at time v1 -----
> class Point {
> constructor(x, y)
> this.x = x;
> this.y = y;
> }
> equals(otherPt) {
> return this.x === otherPt.x && this.y === otherPt.y;
> }
> }
>
> class ColoredPoint extends Point {
> constructor(x, y, color) {
> this = new super(x, y);
> this.color = color;
> }
> // whether we override equals here is not the issue
> }
>
> ---- at later time/revision v2 ----
> class Point {
> constructor(x, y, fudgeFactor = 0.000001) {
> this.x = x;
> this.y = y;
> this.fudgeFactor = fudgeFactor;
> }
> equals(otherPt) {
> return abs(this.x - otherPt.x) <= fudgeFactor &&
> abs(this.y - otherPt.y) <= fudgeFactor;
> }
> }
> --------
>
> Under normal circumstances, as shown above, this is a valid evolution of the
> Point class, even without examining or revising existing clients like
> ColoredPoint. Since the Point constructor had only two non-optional
> parameters, it could normally assume that existing clients had only called it
> with two arguments. Thus, it would normally be assumed compatible with
> existing clients to add new optional arguments. Passing all arguments by
> default breaks this assumption, making the "fragile base class" problem much
> worse.
Mark, making such a change in a v2 would normally be considered bad practice in
any OOP language I've worked with and probably would violate most local style
guidelines. Subclassing for implementation sharing is at best gray box
encapsulation. The developer of a subclass who over-rides and/or super invokes
methods of a base class has to know some things about the base. Ideally, those
requirements are captures in an explicitly documented subclassing contract
provided by the base class' developer, but even if there is no such
documentation there is always an implicit subclassing contract for every class
that is used as a base class.
If you are the developer of a such a base class, there are practical
constraints on if and how you can change your subclassing contract.
If you have access to all code that subclasses your base class, you can make
any changes you want as long as you are willing to updated the code of every
subclass. This is one of the tasks that motivated the invention of OO
refactoring tools. You v2 change would be a change that fall into into this
category. If you have access to all subclasses you can make the change, but
you are also responsible for updating the subclasses.
But if you don't have access to all subclassing clients (for example if you
base class is part of a widely used library or framework) you simply can't
change your subclassing contract in this manner because, as you point out, you
can't update existing client code that depends upon the existing contract.
Whether or not auto new super occurs, the problem still exists as a subclass
client may well have explicitly coded `new super(...arguments)` in its subclass
constructor. Arguably, such a subclass would be operating within the rules of
the implicit subclassing contract of the v1 Point as its parameter list implies
that it will pay attention to only two arguments. If the v1 developer wanted
to future proof its constructor it should have stated it as `constructor (x,y,
...reservedForTheFuture)`. Note that this general problem applies to all
methods that might be super invoked, not just constructors.
To me, this issue is one of ease of use for the most common use case versus a
slight refactoring hazard for a rare, and and likely ill-advised design change
pattern. The most common use case is a subclass that simply adds an additional
constructor parameter corresponding to an additional instance variable. And it
that case, most people we shown the alternatives to prefer this:
```js
class ColoredPoint extends Point {
constructor(x, y, color) {
this.color = color;
}
}
```
over
```js
class ColoredPoint extends Point {
constructor(x, y, color) {
this = new super(x, y);
this.color = color;
}
}
```
Allen
>
> The special case where the super(...arguments) is ok, even needed, is when
> the base class constructor already has a rest parameter.
>
> EIBTI applies forcefully here.
>
> --
> Cheers,
> --MarkM
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss