Minimal Classes as Constructors (was: Re: Classes as Cosntructors)

# Herby Vojčík (13 years ago)

Luke Hoban wrote:

In the discussion of max/min classes at the March TC39 meeting, there was support for minimal class syntax, but a couple concerns with max/min classes in particular.

One category of concern is the (intentional) bare-bones nature of max/min. In this case though, I think it has been demonstrated that additional concepts (class properties, privates, prototype properties, etc.) can be added to max/min later, if and when experience shows them to be needed.

The other category of concern is that max/min decides the core syntactic use of the valuable 'class' reserved keyword in the language. Max/min chooses to use 'class' for a new kind of block with a nested constructor, instead of as direct extensions of the notion of constructor function.

I've raised the class as constructor alternative approach before, and it's something that a few teams I've worked with inside Microsoft have advocated. Since a choice on approach for classes will decide the foundation upon which the class keyword is used in the language going forward, I did a writeup of the alternative syntactic approach at strawman:minimal_classes_as_constructors for comparison.

Here's one of the examples from the write-up:

 class SkinnedMesh(geometry, materials) extends THREE.Mesh(geometry, materials) {

   // properties on the instance object
   public identityMatrix = new THREE.Matrix4();
   public bones = [];
   public boneMatrices = [];

   // ... note, this is the constructor body, statements are allowed here

   // methods on the prototype object
   public update(camera) {
     // ...
     super.update();
   }
 }

Classes as constructors aims to align more closely with existing 'function' syntax, augmenting with the ability to declaratively specify members of the class. Importantly though, methods (and accessors) defined in the class body are bound as prototype properties, not instance properties. This can lead to more succinct classes in many cases, and keeps the notion that a class is primarily a constructor function.

Luke

When I think of this, it looks too heavy to me.

Why use public foo = "bar"; sequence, we can use this.{...}; Why use class keyword when this does not do anything more than function keyword (that is, define a constructor method)? Why put super call into extends when we have normal "super(whatever)" call?

So everything can be done as-is, with the only exception, that being the concise methods that are to be put into the prototype. But since it is the only problem, it can be solved easily: just allow concise method definitions in body of a constructor function (and put the in the prototype), and voila - you have a class:

   function SkinnedMesh(geometry, materials) extends THREE.Mesh {

     // ... note, this is the constructor body,
     // statements are allowed here

     super(geometry, materials);

     // properties on the instance object
     this.{
       identityMatrix: new THREE.Matrix4(),
       bones: [],
       boneMatrices: []
     };

     // methods on the prototype object
     update(camera) {
       // ...
       super.update();
     }
   }

If the parsing is the problem and [NoNewLineHere] is not an option, then it may be possible to use "public" or even "class" ;-) keyword to prefix such concise methods.

So, what would those "few teams [...] inside Microsoft" say to this?

Herby

P.S.: Yes, there is no extends for functions, but I keep saying there should be one. For the moment, it can be supplemented with <| but only for function expressions.

# Rick Waldron (13 years ago)

On Tue, May 22, 2012 at 3:11 PM, Herby Vojčík <herby at mailbox.sk> wrote:

Luke Hoban wrote:

In the discussion of max/min classes at the March TC39 meeting, there was support for minimal class syntax, but a couple concerns with max/min classes in particular.

One category of concern is the (intentional) bare-bones nature of max/min. In this case though, I think it has been demonstrated that additional concepts (class properties, privates, prototype properties, etc.) can be added to max/min later, if and when experience shows them to be needed.

The other category of concern is that max/min decides the core syntactic use of the valuable 'class' reserved keyword in the language. Max/min chooses to use 'class' for a new kind of block with a nested constructor, instead of as direct extensions of the notion of constructor function.

I've raised the class as constructor alternative approach before, and it's something that a few teams I've worked with inside Microsoft have advocated. Since a choice on approach for classes will decide the foundation upon which the class keyword is used in the language going forward, I did a writeup of the alternative syntactic approach at doku.php?id=strawman:minimal_ classes_as_constructorsstrawman:minimal_classes_as_constructors for comparison.

Here's one of the examples from the write-up:

class SkinnedMesh(geometry, materials) extends THREE.Mesh(geometry,

materials) {

  // properties on the instance object
  public identityMatrix = new THREE.Matrix4();
  public bones = [];
  public boneMatrices = [];

  // ... note, this is the constructor body, statements are allowed

here

  // methods on the prototype object
  public update(camera) {
    // ...
    super.update();
  }

If you write this without inline comments, there is actually no way to determine which properties, methods and accessors are being defined on the instance vs. prototype by just reading the code:

class SkinnedMesh(geometry, materials) extends THREE.Mesh(geometry, materials) {

public identityMatrix = new THREE.Matrix4(); public bones = []; public boneMatrices = [];

public update(camera) {

super.update();

} }

Whereas max/min classes are very clear in this regard, additionally building on what we already know, while acting as an encapsulation of current existing patterns:

class SkinnedMesh extends THREE.Mesh {

constructor(geometry, materials) {

super(geometry, materials);

this.identityMatrix = new THREE.Matrix4();
this.bones = [];
this.boneMatrices = [];

}

update(camera) {

super.update();

} }

 }

Classes as constructors aims to align more closely with existing 'function' syntax, augmenting with the ability to declaratively specify members of the class. Importantly though, methods (and accessors) defined in the class body are bound as prototype properties, not instance properties. This can lead to more succinct classes in many cases, and keeps the notion that a class is primarily a constructor function.

Luke

When I think of this, it looks too heavy to me.

The repeated use of "public" is overwhelming, considering everything is "public be default" in JavaScript

Why use public foo = "bar"; sequence, we can use this.{...};

The mustache/monocle is not harmonized

Why use class keyword when this does not do anything more than function keyword (that is, define a constructor method)?

This is almost exactly what I thought when I looked at this syntax this morning.

Why put super call into extends when we have normal "super(whatever)" call?

So everything can be done as-is, with the only exception, that being the concise methods that are to be put into the prototype. But since it is the only problem, it can be solved easily: just allow concise method definitions in body of a constructor function (and put the in the prototype), and voila - you have a class:

 function SkinnedMesh(geometry, materials) extends THREE.Mesh {

   // ... note, this is the constructor body,
   // statements are allowed here

   super(geometry, materials);

   // properties on the instance object
   this.{
     identityMatrix: new THREE.Matrix4(),
     bones: [],
     boneMatrices: []
   };

   // methods on the prototype object
   update(camera) {
     // ...
     super.update();
   }
 }

If the parsing is the problem and [NoNewLineHere] is not an option, then it may be possible to use "public" or even "class" ;-) keyword to prefix such concise methods.

So, what would those "few teams [...] inside Microsoft" say to this?

Herby

P.S.: Yes, there is no extends for functions, but I keep saying there should be one. For the moment, it can be supplemented with <| but only for function expressions.

Similar to the mustache/monocle, the triangle is not harmonized.