extends keyword instead of <superclass ... >

Dmitry A. Soshnikov dmitry.soshnikov at gmail.com
Mon Mar 28 13:53:07 PDT 2011


On 28.03.2011 0:05, Brendan Eich wrote:
> On Mar 27, 2011, at 11:33 AM, Juan Ignacio Dopazo wrote:
>
>> On Sat, Mar 26, 2011 at 6:31 PM, Dmitry A. Soshnikov 
>> <dmitry.soshnikov at gmail.com <mailto:dmitry.soshnikov at gmail.com>> wrote:
>>
>>     Why not just to use already reserved `extends` keyword for
>>     specifying a superclass? These XML-like braces looks not so elegant.
>>
>>
>> I asked this question a couple of days ago. The answer is quite 
>> simple. Object initializer extensions are more than just constructor 
>> syntax. They allow you to create complex objects without all 
>> the hassle in (function(){}()). So the constructor syntax was made 
>> this way to be consistent with object initializer syntax.
>
> The meta syntax (e.g., var obj = {<proto: p>, key: val}) is not 
> inconsistent with initialisers, it's an extension to them. But it's 
> not the only self-consistent extension. Dmitry mentioned letting the 
> meta properties appear to be regular key: value pairs but 
> distinguishing the keys with @ or #.
>
> Allen makes the point that class D extends B {...} may look too much 
> like languages where it means something quite different. That's true, 
> but I am not sure JS should be so special that it seems to mix bits of 
> those languages into one (of several conceivable) extensions to 
> initialiser syntax:
>
> class D {<superclass B>};
>
> Whatever you think of the meta section, the leading 'class D {' 
> telegraphs influence from, and just familiarity with, those other 
> languages. And I don't think that is a bad thing even if semantics differ.
>
> Just changing 'class' to 'constructor' (adding a new 
> perhaps-only-contextually reserved word, and a long one at that) is 
> not the issue. Sure, doing that would in a text-only way make the 
> syntax not look like any other language, exactly. But ignore the skin: 
> the bones look familiar, going back to C structs.
>
> Now add some notion of inheritance and you're following the C++ "body 
> plan".
>

Exactly. "Classes" are not about just the "class" keyword, but about the 
_ability to classify_, i.e. to program in classified (i.e. with 
object-patterned programming). JS supports (and supported all these 
years both approaches: delegation-based prototypal (i.e. unclassified or 
chaotic code reuse) and classical (classified or systematized code reuse).

Thus, a "class" in JS is a pair of "constructor function + prototype". 
 From this viewpoint, e.g. classes in Python (or CoffeeScript) are just 
syntactic sugar of the same delegation-based inheritance used in JS. And 
this means that JS also may have this sugar -- to allow users to program 
in classified manner (if they need to). So there's no a big difference 
between these languages and therefore keyword `extends` may fit 
absolutely normally.

Here how I see classes syntactic in JS (a combination of Coffee's sugar 
+ Java's syntax, since we can't eliminate it).

Notes:

I think that usage of thing like: class method fromString() { .. } are 
to verbose.
Don't think we need another keyword `method` at all.

Also I used a syntactic sugar for `this` keyword as `@`. This `at` 
allows easily to define and distinguish class- and instance- methods. 
The rule is simple: if a property/method inside the class body starts 
with @ -- it's the class's property/method (i.e. `this` refers to 
class). In other case -- it's an instance method. @ evaluated inside the 
instance method refers of course to the instance.

Here's a small example with sugared (on the left hand) and desugared (on 
the right hand side) views: http://bit.ly/hvS7hl Take a look please.

And below is just an example without the desugaring. Thus, the definiton 
itself is in declarative form. Also I think it's good to provide both 
dynamic and static classes. By default I used dynamic classes, so 
`static` keyword is explicit.

In the example I also used `include` keyword as an ability to mixin some 
module as a direct ancestor of an instance, i.e. before the class in the 
hierarchy. Mixins/traits will allow to reuse the code horizontally (not 
only with a single vertical inheritance "tower").

/* ------------------------------------------------------
  * Class Point definition
  * ------------------------------------------------------
  */

class Point {

     /**
      * Class method (placed on constructor function)
      */
     @fromString: function (s) {
         return new Point(parse(s));
     }

     /**
      * Instance intializer (aka "constructor")
      */
     initialize: function (x, y) {
         @move(x, y);
     }

     /**
      * Simple instance method (placed on prototype)
      */
     move: function (x, y) {
         @x = x;
         @y = y;
         @repaint();
     }

     /**
      * Class property (placed on constructor function)
      */
     @x: 10
}

/* ------------------------------------------------------
  * Class Point3D definition
  * ------------------------------------------------------
  */

static class Point3D extends Point {

     include Comparable;

     /**
      * Class static property
      */
     @instances: []

     /**
      * Instance intializer (aka "constructor")
      */
     initialize: function (x, y, z) {
         super(x, y);
         @z = z;
         @class.instances.push(@); // save the instance
     }
}

/* ------------------------------------------------------
  * Examples:
  * ------------------------------------------------------
  */

// create new 3D point
let point = new 3DPoint(10, 20, 30);

console.log(point); // "[instance 0x1382 of Point3D class]"

// inherited method

point.move(100, 200);

// introspect the class

console.log(point.class); // "[class Point3D]"
console.log(point.class === Point3D); // true

// instrospect the super class

console.log(point.class.super); // "[class Point]"
console.log(point.class.super === Point); // true
console.log(Point3D.super === Point); // true

console.log(point instanceof Point3D); // true
console.log(point instanceof Point); // true

// class method

let p = Point.fromString("10-20");
console.log(p.class); // "[class Point]"

// analyze class methods and properties
console.log(Point.classMethods); // ["fromString"]
console.log(Point.classProperties); // ["x"]
console.log(Point.instanceMethods); // ["move"]

console.log(Point3D.classProperties); // ["instances"]


How does it look like? Do we need such a sugar? For both -- classes and 
`this` as `@`? Then # can be used for meta-properties on initialisers.

Dmitry.


> Do we really need to look different yet still have bones that look so 
> familiar? I am not convinced.
>
> The strongest case for extending initialiser syntax is that it is 
> "nearly declarative" today. That suggests strongly making the 
> extension fully declarative, i.e., not usable as an expression. And 
> that, all else equal (never is, but:) says to consider class D extends 
> B {...}. My 2 cents.
>
> /be
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110329/e8b35602/attachment.html>


More information about the es-discuss mailing list