(I'm going to write this up as a strawman, this list gets first shot at it...)


Introduction

For ES.next we all want to provide better ways for ES programers to define 
named abstractions over objects.  One way to do this that we have discussed is 
"Object exemplars" 
(http://www.mail-archive.com/[email protected]/msg10365.html )

Object exemplars essentially implement the self language style of object 
abstraction where prototype objects are given names and used as the named 
abstraction that represents a family of related objects.  Object exemplars 
typically are instantiated by applying the new operator to a specific named 
instance of the abstraction.  Object exemplars also typically define an 
initialization method that is called when a new instance is created.  For the 
ES implementation of object exemplars, this initialization method is named 
"constructor".  For example:

let Point = {
     x:0,
     y,0,
     constructor(x,y} {
         this.x=x;
         this.y=y;
     }
};

let p = new Point(1,2);

Using object exemplars, the named abstraction is itself an instance of the 
abstraction. Some people seem to be perfect happy to only have and use this 
form of object abstraction.  However, others prefer to think in a more 
"classical" style where the named object representing an abstraction is a 
distinct kind of object that is not itself an instance of the abstraction. In 
practice, these two views of object abstraction are very closely related/  For 
example, a very simple addition to the above definition essentially turns Point 
into a "function exemplar".  Function exemplars can also be thought of as 
"class exemplars":

let Point = {
     x:0,
     y,0,
     constructor(x,y} {
         this.x=x;
         this.y=y;
     }
}.constructor;   //<----------- note added property reference

let p = new Point(1,2);  //new operator applied to a constructible function 

However, people that prefer the "classical" style will reasonably point out 
that it is both easy to forget the trailing property accessor in this 
definition and that even if it is there a reader is likely to not notice it.

This proposal provides a solution to these  and other related issues that allow 
object exemplars and class/function exemplars to have equivalent status and to 
be  built upon the same underlying syntax and semantic mechanisms.

The class Operator

The class operator is used in a new variant of UnaryExpresson:

   UnaryExpression :
           class UnaryExpression
           ...

The semantics are:
 1. if UnaryExpression is undefined or null, return the value of 
UnaryExpression.
 2. Let obj be ToObject(UnaryExpression)
3. Return the result of calling the [[Get]] internal method of obj with 
argument 'constructor'

Using the class Operator

Prefixing an object exemplar with the class operator turns it into a class 
exemplar:

let Point = class {
     x:0,
     y,0,
     constructor(x,y} {
         this.x=x;
         this.y=y;
     }
};

The precedence of the class operator and the semantics of <| means that it also 
works as expected with object exemplars that specify an inheritance 
relationship:

let Point = class AbstractPoint <| {
     x:0,
     y,0,
     constructor(x,y} {
         this.x=x;
         this.y=y;
     }
};

In the above example  Point inherits from AbstractPoint.  If AbstractPoint is a 
function then this means that the [[Prototype]] of Point is AbstractPoint and 
that the [[Prototype]] of Point.prototype is AbstractPoint.prototype. If 
AbstractionPoint is an object exemplar it means that the [[Prototype]] of Point 
is AbstractPoint.constructor and that the [[Prototype]] of Point.prototype is 
AbstractPoint.


The class operator  can prefix any UnaryExpression, not just object literals.  
That means that the class operator can be used to classify objects:

if (class p === Point) ...

Note that many object-oriented abstraction designers consider this for of class 
testing to be an anti-pattern. 

It also works with instances of the standard ES built-in constructors:

if (class new Array(1,2,3,4) === Array) ... //this will be true

so are these:

if (class [1,2,3,4] === Array) ...
if (class [].pop === Function) ...

It also works with private value types:

if (class 1234 === Number && class false === Boolean && class "Hi" === String) 
... //all true

but note that

if (class null === Object) ... 

is false.

You can use the class operator to determine if two objects are instances of the 
same exemplar:

if (class p === class q) ...

Note that this works for instances of both class and object exemplars.  
However, if you want to test if an object is an instance of a specific named 
object exemplar then you need to remember that  such exemplars are prototype 
instances rather than constructor functions.  Of course, if you prefer object 
exemplars you are probably used to thinking in that prototypal style. You would 
express this as:

if (class p === class Point) ...  //for this example, assume the very first 
definition of Point

Finally, you might use class to create a new instance of the same exemplar as 
some other known object:

let mine = new class theirs;

This works the same regardless of whether the value of "theirs" is an object or 
class exemplar.

Relationship between the class and instanceof operators

There isn't one.  They are different operators.  class is simply a short hand 
for accessing an object's constructor property  instanceof tests a specific 
inheritance relationship. 



_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to