Finding a "safety syntax" for classes

Herby Vojčík herby at mailbox.sk
Tue Mar 20 11:13:40 PDT 2012



Russell Leggett wrote:
> Is it possible that we can come up with a class syntax that we can all
> agree is better than nothing, and importantly, leaves possibilities open
> for future enhancement? As a “safety syntax” this doesn’t mean we stop
> trying to find a better syntax, it just means that if we don’t find it
> then we still have something – something that we can make better in ES7.
>
> I would propose that the absolute minimal requirements would be:
>
>     * has a declaration form that uses the class keyword and an
>       identifier to create the class
Why to rule out other possibilities (though I understand this one is the 
"least surprise" one)?
>     * has a body that can include both the constructor function, as well
>       as any instance (prototype) methods – including getter and setter
>       properties
>     * can declare the class as a subclass of a another class (probably
>       with the extends keyword)
>     * super is available from any of the methods or constructor function
Ok.
> The following is an example from the CoffeeScript website, and just
> converted to what seemed like a logical JS version:
>
> class Animal {
>      constructor(name){
>          this.name = name;
>      }
>
>      move(meters){
>          alert(this.name + " moved " + meters + "m.");
>      }
> }
>
> class Snake extends Animal {
>      constructor(name){
>          super(name);
>      }
>
>      move(){
>          alert("Slithering...");
>          super.move(5);
>      }
> }
>
>
> class Horse extends Animal {
>      constructor(name){
>          super(name);
>      }
>
>      move(){
>          alert("Galloping...");
>          super.move(45);
>      }
> }
>
>
> let sam = new Snake("Sammy the Python");
>
> let tom = new Horse("Tommy the Palomino");
>
> A few things that are different from CoffeeScript:
>
>     * if there is no constructor, it doesn’t automatically pass
>       arguments up to the parent constructor. I think that would be nice
>       but more controversial.
A thing for discussion. Clear is clear, but you define the constructor 
anyway (you have to, it's the JS way). Maybe there should be extends* to 
say 'auto-generate forwarding, not clear one'.
Though this is not the part of "safety" plan.
>     * to call super on a method you have to indicate the method super.move
>     * while not obvious in the example, I would say the class body should
>           o be its own construct, not just an object literal - this
-1. See more below.
>             makes it easier to have methods without ,’s and be
>             future-proof for whatever we might want later
I have a lot of reasons (gut instinct, too, but also some though 
experiments on how things get powerful and concise things can be if 
classes automaticall had all the possibilities of (potientially 
revved-up) object literals [1]).
So I need to see a really strong argument for abandoning the cause of 
"body of class should be the same as the body of object literal (with 
possible little numbers of changes)".

So my -1 holds if you want to add anything that goes beyond the 
object-literal syntax, and I'd give -0.66 in case where you would 
restrict it too much.

If you restrict it to only hold constructor and methods, it is still a 
compatible (though stripped) object-literal - you can have methods there 
(constructor is nothing special, just a method named 'constructor'; the 
magic of class keyword grants it [[Construct]] and .prototype created 
from {} block and according to object literal syntax you can have 
methods there without comma), so this would be -0.66.

Without this restriction it would more or less be the same as proposal 
"3." in the thread unhappily named 'u' (my mail client probably did 
something wrong):

3. 'class Name {...} [static {...}]' as a quasi-sugar for 'Name.prototype
.{...} [.constructor.{...}] with Name body derived from constructor
method in first {...}; always returning the constructor':
(liberal use of <| for class declarations as well)

private arr;

class List {
   constuctor (n) {
     this. at arr = n === +n ? new Array(n) : [];
   }
   at (i) {
     i = +i;
     if (i>=0 && i<this. at arr.length) { return this. at arr[i]; }
     else throw "Out of bounds: "+i;
   }
   size () { return this. at arr.length; }
} static {
   from (array) {
     var r = new this();
     r. at arr = array;
     return r;
   }
};

private writeArr, readOffset;

List <| class Queue { // no problem if here is 'extends', but
                       // I'd like it for function declaration, too, then
                       // as in thread "extends with functions"
   constructor () {
     super();
     this. at writeArr = [];
     this. at readOffset = 0;
   }
   at (i) { /* needs redefinition */ }
   size () {
     return super.size() - this. at readOffset + this. at writeArr.length;
   }
   push (elements) {
     return writeArr.push.apply(writeArr, elements);
   }
   shift () {
     //reads from arr; shifts []->writeArr->arr if empty
   }
}

// Queue inherits from, needs no static if it does not want something
additional



I silently assume here that extends creates, of course, double chain 
(constuctor inherits as well as prototype inherits, not just the latter)

>           o only allow a constructor function and methods - nothing
>             else. No public/private fields. No worrying about var x =
private can be done as above - out of class - it does not need as part 
of its syntax
>             {a:b} inside the class body – if it should be allowed, what
>             the syntax should be etc. With the "safety syntax", less is
>             more as long as it gets accepted.
>
> So what do you say people? Is it safe enough? One of the biggest
> arguments I’ve heard against rushing in a class syntax now is that once
> its in we have to keep supporting it. I say that this is small enough we
> won’t regret it, and makes it possible to do a lot more in the future.
It's too small. Whenever I want a shared field in prototype (other than 
method), I still must

MyClass.prototype.{
   sharedBar: 0,
   sharedBaz: ""
};

This makes its inclusion a bit questionable (same for statics).

Yes, we can go in little steps... but lots of them we already have 
(super expressions are already planned to be orthogonal to classes), and 
I think the next small step should be 'extends' for function 
declarations (which, unless <|, explicitly says "I am creating double 
chain here, in the spirit of 'classical' class inheritance; and if thing 
after extends is not constructor, I throw").

> If something more substantial can be agreed on soon enough to make it
> into ES6, even better, but maybe we can at least have a backup plan.
>
> - Russ

Herby

[1] http://blog.herby.sk/blosxom/Programming/ES-next/empowered-data.html
This adds functional data-definition power to object literals and as a 
consequence, trait based composition is in the classes for free


More information about the es-discuss mailing list