An experiment using an object literal based class definition pattern

Bob Nystrom rnystrom at google.com
Fri Aug 5 11:43:19 PDT 2011


>
> Particular, if a programmer sets up an editor template that inserts:


If we're OK with relying on tooling to type the boilerplate for us, I'm not
sure there's much reason to add any new sugar at all. At that point, we
could just set up the tools to insert:

  function classname() {
    subclass.constructor.call(this);

  }

But, personally, I'm not OK with leaning on tools. Sure the machine can type
the boilerplate for me, but I still have to *read* it with my *eyes*. (And I
read a lot more code that I write.) If I could have a tool that would read
that boilerplate pattern back in and spit out something declarative for me
to read, I'd be happy. But, then, that's pretty much exactly what we're
talking about with a class proposal.

For example, here's what SkinnedMesh would look like with classes and
sections:

  class SkinnedMesh extends THREE.Matrix4.Mesh {
    constructor(geometry, materials) {
      super(geometry, materials);

      this.identity.Matrix = new THREE.Matrix4();
      this.bones = [];
      this.boneMatrices = [];
    }

    update(camera) {
      ...
      super(update);
    }

  class:
    default() {
      return new this(THREE.defaultGeometry, THREE.defaultMaterials);
    }
  };

I like the idea of giving users primitives and letting them build their own
patterns (and I think that use case is important to support in the
language). But for things where a pattern is already established, I really
like letting users express that directly in a notation that's easy on the
eyes. To me, the above is pretty good for that.

And, some of the progress we have been making has the feel of committee
> compromises in order to make progress rather than strong cohesive design.


That's unfortunate. :(

A few of the class proposals have felt like fairly solid cohesive designs to
me, but I may have a different aesthetic here. My hunch is that cohesive to
you (and others) means something like "a small number of orthogonal
primitives that I can combine to get a combinatorial number of different
usable configurations".

It's like magnetic poetry, where you can arrange the words in an infinite
number of combinations. Most of the class proposals aren't in that vein.
They're closer to mad-libs: you can fill in the blanks but the structure is
pretty fixed.

The question then is should we add a feature like this that isn't that
open-ended? My belief is that it in this case we should. It's been said that
design patterns show a lack in the language. With ES, "classes" are a very
common pattern, and if we enable the language to acknowledge that, we can
make our users' lives easier.

Given the availability of those extensions, who knows what sorts of
> innovative abstraction ideas will emerge from the same JS programmers who
> accomplished so much using just ES3.


I don't think this is necessarily an either/or choice. We can have both more
primitive object extension operators like <| that you propose to serve the
avant garde who want to build novel ideas from scratch while also providing
a declarative form or two for the well-trod middle ground where it's clear
that many users are expressing the same thing over and over again.

To me, those two work in harmony with each other. If I've got a terse
declarative syntax for common stuff, I can spend less time reading and
writing that boring boilerplate and have more time to spend using <| and
other features to express the things that are unique to my app. As it is
now, I spend most of my time just wading through
MyClassThing.prototype.someProperty = ...

Possibly more importantly, if we bake classes and an inheritance scheme into
the language, then it becomes the standard. That makes re-use easier. Long
analogy...

In C++, I always found library re-use a nightmare. Library A would use smart
pointers, but I was using my own ref-counting. Library B wanted me to
managed its objects' memory but library C expected to manage itself. Library
D wanted an allocator, Library E wanted to use its own.

Java just said "you get GC, take it or leave it". People said, "but you can
implement your own GC in C++! Java isn't flexible!" And that's true. Memory
management got pretty much taken out of your hands. But it also solved a ton
of library interop problems. Now I could just pass objects to and from
different libraries easily and re-use got much better.

With classes in JS, I think we have a similar opportunity. If we provide a
default way to define and inherit classes, I'll be able to have my code
inherit from classes in libraries A, B, C without having to worry about
whether they do Dojo-style or Closure-style, or whatever.

Rather than baking into ES.next a syntactic class abstraction that is
> largely inspired from static OO languages experience lets just make these
> primitives available and see what happens in the real world.  If a single
> dominate abstraction pattern emerges then we can consider baking it into
> ES.next.next syntax.


Haven't we done that with ES1-3 already? Users have had 15 years of
prototypes and what they chose to do was make classes. We've got Closure's
goog.extends(), Dojo's dojo.declare(), Prototype's Class.create() (ironic,
given the name of the framework!), JS.Class, and CoffeeScript's class
syntax. How many more cows do we need before that path is ready for paving?

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


More information about the es-discuss mailing list