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

Mark S. Miller erights at google.com
Sun Aug 24 16:09:42 PDT 2008

On Sun, Aug 24, 2008 at 3:22 PM, Kris Zyp <kris at sitepen.com> wrote:
> I don't see why it is better to have classes be sugar for closured object
> literals rather than prototype based structures. It seems the benefits that
> are being sought after are auto-binding on method extraction and private
> method creation.

I'm not sure what you mean by "private method creation", so I'm not
sure whether you've covered the other main motivation: encapsulated
instance variables. ES3 has only one encapsulation mechanism: lexical
capture by closures. ES4 achieved class-private instance variables by
use of namespaces. My earlier Classes-as-Sugar proposal suggested
using the prototype chain much as you do here, and adding another
property attribute to mark a property as "private". This gives
instance-private rather than class-private variables, which is the
safer default for a dynamic language. The new objects-as-closure sugar
also gives instance-private encapsulation, and without proposing any
new semantic state. I think it is better in all ways.

> Both of these can be attained with prototype-based class
> desugaring. If you really you want auto-binding on method extraction (which
> IMO is of very minimal value), why not do it this way and keep class
> semantics much closer to the prototype techniques used in JavaScript today:
> (function(){
>   // desugared Point class
>   Point = function(){};
>   function privateMethod(){
>   }

I don't understand the point you're making with privateMethod. How do
you provide encapsulated per-instance state?

> However, I would prefer |this| instanceof checking instead auto-binding on
> extraction. Rather than binding on extraction, class methods would always
> have an implicit check to make sure they were called with an object that was
> an instance of (instanceof) the class:

In the absence of inheritance, I suppose this is safe. But it is not
safe when combined with inheritance. If b is an instance of B which
extends A, and B overrides A.foo(), then the author of B should be
able to assume that no one outside b can call A.foo() on b. Your
proposal would still allow an attacker to A.foo.call(b), which might
violate b's integrity.

> By using type checking instead of binding on extraction, this would allow
> functions that recieve a function/method as parameter to apply the function
> to appropriate compatible object instance with apply or call:
> function showCoordinateOnSelect(coordinateGetter){
>   table.onclick = function(event){
>       var point = getPointForClick(event);
>       alert(coordinateGetter.call(point));
>   }
> }
> ...
> showCoordinateOnSelect(Point.prototype.getX);

Just use a normal function instead of a method.

>> It is to cater to mutable function critics, since they're right ;).
> That may be, but it seems like an orthogonal feature, seems like it should
> be discussed separately to avoid confusing the goal of basic class
> desugaring.

It's actually not orthogonal. We freeze methods by default for the
same reason that we freeze the object by default: so that clients of
an instance of a class, by default, can only interact with each other
by virtue of sharing that instance according to the behavior
explicitly provided by that instance.

But it is sufficiently separate that it can be discussed separately.


More information about the Es-discuss mailing list