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

Reply via email to