How much sugar do classes need?

Peter Michaux petermichaux at gmail.com
Sun Nov 23 11:27:56 PST 2008


2008/11/22 Mark S. Miller <erights at google.com>:

>   const Point = let {
>     // after desugaring
>     let privClassVar = 1;
>     const privClassConst = -1;
>     Point.pubClassConst = -3;
>
>     function Point(x, y) {
>       let privInstVar = 2;
>       const privInstConst = -2;
>
>       const self = Object.create(Point.prototype);
>       Object.defineProperties(self, {
>         toString: {value: Object.freeze(function() {
>           return '<' + self.getX() + ',' + self.getY() + '>';
>         })},
>         getX: {value: Object.freeze(function() { return x; })},
>         getY: {value: Object.freeze(function() { return y; })},
>         pubInstVar: {value 4, writable: true, enumerable: true},
>         pubInstConst: {value: -4, enumerable: true},
>       });
>       Object.preventExtensions(self);
>       return self;
>     }
>     Object.freeze(Point);
>   };

I jumped straight to looking at your proposed sugar and that lead me
to some confusion because the above unsugared code is not the pattern
I think the sugar should be coating. I think it is good to look at
both the sugared and desugared versions at the same time.

With the above code and in the sugared code, an instance methods
accesses a public instance member like "self.getX()" in toString. This
is verbose and this brings up the issue of whether or not the idea of
properties and variables should be blurred. In this case of classes, I
think the goal *is* to blur them so that access to public members is
non-verbose from anywhere inside the class. As an example, I'll
rewrite the above desugared code so that access is easy. I'm leaving
out class properties. I think the following is the pattern the sugar
should be coating.

const makePoint = function(privX, privY) {

  const self = Object.create(Point.prototype);

  let privInstVar = 2;
  const privInstConst = -2;

  function toString() {
    // no need for "self."
    return '<' + x() + ',' + y() + '>';
  }
  Object.defineProperties(
    self,
    "toString"
    {value: Object.freeze(function() {return toString();})});

  function x() {
    return privX;
  }
  Object.defineGetter(
    self,
    "x"
    {value: Object.freeze(function() {return x();})});

  function y() {
    return privY;
  }
  Object.defineGetter(
    self,
    "y"
    {value: Object.freeze(function() {return y();})});

  var pubInstVar = 4;
  // not sure how to write the next section properly with
  // the necessary attributes.
  Object.defineGetter(
    self,
    "pubInstVar",
    {value: Object.freeze(function() {return pubInstVar;}),
     writable: true,
     enumerable: true});
  Object.defineSetter(
    self,
    "pubInstVar",
    {value: Object.freeze(function(val) {pubInstVar = val;}),
     writable: true,
     enumerable: true});

  var pubInstConst = -4;
  Object.defineGetter(
    self,
    "pubInstConst",
    {value: Object.freeze(function() {return pubInstConst;}),
     enumerable: true});

  Object.preventExtensions(self);
  return self;
};

With the above code, the "public" keyword sugar has obviously greater
purpose. All of the mentions to "self" disappear. The aggregation of
that object's properties is almost automatic. The use of "private"
does the work.


class Point(privX, privY) {
  let privInstVar = 2;
  const privInstConst = -2;

  public function toString() {
    return '<' + x() + ',' + y() + '>';
  }

  public get function x() {
    return privX;
  }

  public get function y() {
    return privY;
  }

  public var pubInstVar = 4;

  public const pubInstConst = -4;
};

All the interleaving code that establishes "self" and adds properties is gone.

One way to interpret my desugared and sugared versions is that all
members can be accessed as though they are private. Public members
should be accessible uniformly the way that private members are
accessed. An instance has permission to access all of its members and
shouldn't need to work hard to access the public members. The use of
"public" is aggregating some of the private members that should also
be made available publicly.

----

With the sugar in the wiki page for public function members and
function expressions, things become extremely compact

class Point(privX, privY) {
  let privInstVar = 2;
  const privInstConst = -2;
  public toString() '<' + x() + ',' + y() + '>';
  public get x() privX;
  public get y() privY;
  public pubInstVar = 4;
  public const pubInstConst = -4;
};

And I think that is looking quite appealing.

Peter


More information about the Es-discuss mailing list