Feedback on Subclassing" Built-in Constructors

Allen Wirfs-Brock allen at wirfs-brock.com
Thu Jun 21 13:42:10 PDT 2012


On Jun 21, 2012, at 8:48 AM, David Bruant wrote:

> Hi,
> 
> I have read the recent "Subclassing" Built-in Constructors" page [1] and I have some feedback.

Well, that page is still is work in progress.  But you feedback is still appreciated. 

> This page exhibits a distinction that wasn't clear in my mind before reading it: some internal properties can be added lazily like the ones for dates while some (essential internal methods) cannot.

Yes, but mainly for implementation reasons.  At least of the essential internal properties are used so frequently that their implementation must be highly optimized. Lazy updates to them may still be possible but are likely to have deep implementation impacts with performance implications.


> 
>    class MyDate extends Date {
>       constructor(...args) {
>          // |this| has no internal date property
>          super();
>          // now it does have them and can be considered as a date object, [[NativeBrand]] aside
>       }
>    }
> 
> For constructor of objects that only add internal data properties and additional internal method (like RegExps [[Match]]), this can work fine. However, for objects with different essential internal methods, it cannot work.

Now you're into the part of the document I haven't finished editing...
> 
>    class MyArray extends Array {
>        constructor(...args){
>            // |this| not an array until i've called super(), right?
>            'length' in this; // false
>            this[2] = "yo";
>            this.length = 1; // ? I guess nothing happens except that |this| has a new 'length' property?
>            super(); // If nothing serious happens, the array invariant is broken.
>            this[2] // ?
>            this.length // ?
>        }
>    }
> 
> I don't think there is a way out unless |this| is already an array in which case 'super' is useless.

Well, the validity of any invariants over MyArray are actually the responsibility of its implementors.  But, if Array's constructor is defined carefully generally things happen.  Remember there is actually nothing special about the 'length' property of an Array.  It's the array [[DefineOwnProperty]] internal method is special.  One of the things it does is delete array elements when the value of 'length' is decreased. So for the above scenario if Array constructor was defined with these steps:

   1 Set the [[DefineOwnProperty]] internal method of the this value to the special array version.
   2 Call the [[Put]] internal method of the this object with arguments 'length' and 0.
   3 ...

at step 2 ([[Put]] actually delegates to [[DefineOwnPropety]] ) any elements between 0 and the current length would get deleted and the length would set to 0.  That would still leave element 2 around, but  that element would be ignore by any other array processing algorithms that depend upon length.  Note that  it is already possible for an Array to inherit  numerically indexed properties whose indices are beyond the array length so there is no invariant that all visible array index properties keys are within the length bounds.

But, in this case, I think the main thing is that we can't prevent developers from coding crap.  If they do, it really is their problem as long is we guarantee memory safety. 

Allen



More information about the es-discuss mailing list