ES4 draft meta-issues

Lars Hansen lhansen at adobe.com
Thu Mar 6 13:45:06 PST 2008


Information/discussion item.

In the drafts for predefined classes I've sent out so far, the
interaction between the intrinsic methods and the prototype methods has
more or less uniformly been specified as the prototype calling the
corresponding intrinsic method on its "this" object, for example:

  class C {

    prototype function toString(this:C)
      this.intrinsic::toString()

    intrinsic function toString()
      ...
  }

The thinking was that by using this structure the prototype method can
then take advantage of subclasses that override the intrinsic method
(since the intrinsic is virtual the prototype method picks up the method
in the subclass when calling the intrinsic).  However, this thinking is
flawed.  The meaning of many prototype methods is fixed by E262-3 and
must remain unchanged in E262-4 for compatibility reasons.  An important
example of this is the original Object.prototype.toString method.  Not
infrequently one sees code like this:

  var x = <some object of unknown class, call it "C">
  x.toString = Object.prototype.toString
  x.toString() // expected to return "[object C]"

It's a hack but it can be used to discover class names.  However, if C
overrides intrinsic::toString then this idiom no longer works, because
Object.prototype.toString calls this.intrinsic::toString which is the
overridden method in C, not the one in Object.

As a consequence, I think that the libraries need to be adjusted a
little bit.  Prototype methods should have fixed meanings that depend
only on the type of object they were extracted from, whereas intrinsic
methods can be overridden and can be specified such that they will pick
up overridden methods.  The structure would now be:

  class C {

    prototype function toString(this:C)
      this.private::toString()

    intrinsic function toString()
      private::toString()

    private function toString()
      ...
  }

With this structure, the idiom outlined above would return the expected
string, but (new C).intrinsic::toString() would pick up C's toString
method as expected.  In the absence of overriding, the prototype and
intrinsic methods would work identically, as expected.

There are variations on this pattern; if the prototype method is
generic, then it might forward to a static helper method (since an
instance method would be this-constrained).

The complexity increase of this is annoying but less bad than it might
seem at first glance because the truly huge classes -- Array, String --
already have all the functionality factored as static helper methods,
and the main adjustment is to the prototype methods.  For specification
purposes it will make sense to follow the pattern pretty strictly, but
in a practical implementation it would be more reasonable to duplicate
some functionality, especially for simple methods.

--lars



More information about the Es4-discuss mailing list