Look Ma, no "this" (was: ECMAScript Harmony)

Peter Michaux petermichaux at gmail.com
Mon Aug 25 12:23:16 PDT 2008


On Mon, Aug 25, 2008 at 11:28 AM, Brendan Eich <brendan at mozilla.org> wrote:
> On Aug 25, 2008, at 12:34 AM, Peter Michaux wrote:
>
>> On Sun, Aug 24, 2008 at 9:44 PM, Kris Zyp <kris at sitepen.com> wrote:
>>
>>> Desugared from:
>>
>>> class Point {
>>>  private var x = Math.random();
>>>  function getX(){
>>>      return this.x;
>>>  }
>>>  ...
>>> }
>>
>> Is there any need for the "this."? Some languages allow "this.x" to
>> get out from under the shadow of a local "x" inside "getX". I don't
>> think it is necessary to be able to escape such shadowing and actually
>> increases confusion. If a method is many lines long then the reader
>> may forget that "x" is local and not the instance variable. I would
>> just call the local variable "locx" or "xx" or something different. I
>> would actually rather see the "this." shadow escaping be disallowed.
>
> That might be a good idea.
>
> The bigger question is whether |this| remains at all. The desugarings we
> tend to write on whiteboards use |let self = ...| or similar and |self| as
> the new |this| -- but of course that might collide with a necessary inner or
> outer name. It would be better to gensym the name, but who has time at a
> whiteboard?
>
> To refer to the instance in the sugared language, and there are valid
> use-cases for doing so, we should use |this|. There's no point in
> introducing a new keyword.

If there is a need to refer to the instance then "this" does make
sense. What would be a great success if if there is just no need for
"this" at all. It certainly seems possible to avoid.


> Which gets to a point you raise later, about var
> in class being confusing. If class is the new, higher integrity constructor
> function that induces instance-bound frozen methods, etc., then its syntax
> (by the similarity principle I adumbrated earlier) *should* mimic function:
>
> class Point(x, y) { // parameters to constructor here
>  let r = Math.sqrt(x*x + y*y);
>  let theta = Math.atan2(y, x);
>  function getX() x;
>  function getY() y;
>  // etc.
> }

I was wondering about how the constructor parameter aspects would work
and thought it might work like you have outlined above.

Now there is another problem: differentiating between which variables
are local to the constructor function (that is, transient and garbage
collected after the constructor function is returned (don't know the
technical name for these variables)) and which are properties of the
resulting returned object. I think you know what I'm describing but to
make it more concrete in ES3 I can write

function Point(rad, ang) {
  // some helper functions
  function computeX() {
    return rad*Math.cos(ang);
  }
  function computeY() {
    return rad*Math.sin(ang);
  }
  this.x = computeX()
  this.y = computeY();
}

A naive translation to the sugar might be

class Point(rad, ang) {
  // some helper functions that end up being properties? Problem.
  function computeX() {
    return rad*Math.cos(ang);
  }
  function computeY() {
    return rad*Math.sin(ang);
  }
  var x = computeX()
  var y = computeY();
}

Requiring the programmer to use both "public" and "private" as I did
below might be a solution (though you thought it is verbose) so that
it is clear which variables are part of the constructed objects.

> var or const could be used too, because they can be used in function bodies.
> Class body *is* constructor code. Similarity is good because it builds on JS
> programmers' knowledge of functions, but provides incrementally better
> semantics for the similar syntax. Programmers get the carrot, not the stick
> of gratuitously different syntax.
>
> It will take more than a 2D point class to make the case, but this was along
> the lines of the Oslo discussions on the third day, to desugar as Mark
> proposed on the first (and showed in his post at the head of this thread).

I suggest at least a couple DOM widgets are used (e.g. tabbed pane,
dragdrop list, sortable table) as test examples when discussing class
sugar seriously. The DOM is a big part of the JavaScript world, after
all.


>> In the above code snip it seems that properties will be public unless
>> listed as private. In the security world, whitelisting is considered a
>> best practice as blacklisting can accidentally leave things out in
>> public that should not be.
>
> Not everything in JS is security-critical. JS is used in single-trust-domain
> embeddings, but even on the web, the B&D programming by way of the security
> root password to the tattered "just a scripting language" constitution seems
> like a power-grab :-P. I mixed three kinds of technical politics there, but
> they are all relevant. Different parties are concerned about the common
> good, but we don't all agree on the common good.
>
> Python and Smalltalk don't have private methods by default (or at all), just
> to pick two examples. Should classes as better constructors have this bias?

My gut says yes and I have some vague reasoning that may mature.

In ES3 a nested function is "private" inside the outer function. So
there is some sense of "private by default" already. At least
apparently to me.

function foo() {
  function bar() {}
  //...
}

I have to make special effort to get that bar function out in the open
or in some larger surrounding scope.


> I'm not saying "no", I reserve judgment. It seems to me much depends on the
> module system, if there is one (and there had better be, since in spite of
> being the inevitable source of addressing and loading semantics, the
> <script> tag is not enough for in-language modularity).

No one seemed to response to my post in the thread about modules but
"module" should not equal "file" as HTTP is still expensive and
programmers want to concatenate and minify their scripts.


>> What about the following two options:
>>
>> class Point {
>>   private x = Math.random();
>>   public function getX(){
>>       return x;
>>   };
>> }
>
> Verbose, please pick a default.

Private. Much easier to debug. The issues described above about helper
functions may necessitate declaring both public and private properties
as such.


> Making people type private all the time is
> going to get old (if you think 'function' is too long...).

I don't think "function" is too long. It is shorter than "procedure"
:-) The only unfortunate thing about "function" is they are not really
functions.


>> var Point = class {
>>   private x = Math.random();
>>   public getX = function(){
>>       return x;
>>   };
>> };
>
> This shows a separable and good idea: first-class classes. BTW, you probably
> want 'const Point = class { ... }', and 'class Point...' should make a const
> binding by default (unlike a function definition -- another upgrade).
>
> Another separable point to debate: resolved, classes should freely nest (in
> other classes and functions) and generate new entities each time they are
> evaluated. Just like functions (ignoring or removing the joined function
> object option from ES3).

Great!

>> If only one option could be included I'd *much* prefer the final
>> option as "var" could be changed to "let" so I control the class's
>> scope better.
>
> That's not to say we shouldn't have the named form of class,

No. I was pointing out that having the last form would be really good.

> any more than
> we shouldn't have named functions. Named functions are a special form, as
> close to let rec as you get in JS. You can have mutually recursive named
> functions call one another freely, making forward refs, due to hoisting.
>
> You also get the intrinsic name, useful for diagnostics at runtime and
> harder to infer (really guess, worst-case pick the name of the most relevant
> binding) for anonymous functions.
>
>
>> In either of the last two cases, I imagine that the "Point" variable
>> is pointing to a first-class class objects (which desugars to a
>> constructor function) that I could pass around, yes?
>
> Yes.
>
> There are deeper waters to do with types,

Yes. The parent-child windows issue both declaring the same or
different "class Foo" seems like an important detail. Perhaps provably
making nominal types useless or at least as awkward as instanceof?

> but this is enough for classes.
> Other details need to be worked out, but this is enough to chew on for now.

Peter


More information about the Es-discuss mailing list