Summary: prototypes as classes

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Jun 28 15:56:54 PDT 2011


On Jun 28, 2011, at 8:34 PM, Bob Nystrom wrote:

> I like the simplicity of this, but I'm not crazy about how it merges two distinct objects into one. TodayJS (and most class-based languages) let you distinguish two things:

(actually in the today's most widely used class-based languages (Java, C#, C++) a "class" is no an object at all and don't have properties/fields/polymorphic methods/etc.  they really are just a scoping mechanism.  What you are saying is more typical of many dynamically typed class-based languages).

Note that the goal of the prototype as classes proposals is not to turn JS into more of a class-based language.  Instead it was to solve the same problem that classes solve but in a manner that returns JavaScript closer to its original prototype-based roots.  This was covered in  the message that started the "Prototype as new new class declaration" thread https://mail.mozilla.org/pipermail/es-discuss/2011-June/015135.html  It is probably worth while going back to review those first few messages to get a better chance of what this proposal is really about.

While both the class-based approach and the prototype-base approach allow you to describe an open ended set of similar objects via a named abstraction, the key difference is in what you name.  In the class based approach you name the object that is responsible for creating new instances (the constructor) of the set. In the prototype-based approach you name the prototypical instance of the set. 

The "two objects" you speak of is purely an artifact of how the class-bassed approach works.  It is not a fundamental characteristic of all OO languages.  

When it is useful to have s separate factory object for creating the instances of a prototype-based abstractions, prototype-based languages simply create another object to act as the factory. that object can have private state, addiional public properties for accessing canonical instances, etc. 

In https://mail.mozilla.org/pipermail/es-discuss/2011-June/015195.html  is examine how the self language addressed various situations where "static methods" might be used in a class-based langauges.


> 
> 1. A set of properties relevant to the class itself.
> 2. A set of properties shared by each instance of the class.
> 
> In a class-based language, #1 up there is "static" methods and fields. So when you do something like this in Java:
> 
>   Integer.parseInt("1234");
> 
> The "parseInt" method isn't a method that you can call on an integer, it's a method you call on the Integer class itself.

In self, you would likely do exactly the above.  Integer would be the name of the prototypical integer object and that object would have a method named parseInt.
You then can just say: 
   Integer.parseInt("1234");    //actually in self you would say: Integer parseInt: '1234'.
or you can say
    0.parseInt("1234");
or any other integer object that was conveniently available.

If you didn't want the ability to parse to be a method of integers you would just create a factory object:
    IntegerBuilder.parse("1234");

Why is this worse than a "static method"?

> 
> In Javascript, those are properties on the constructor:
> 
>   function Point(x, y) {
>     this.x = x; this.y = y;
>   }

note that the above isn't a property of the constructor, it is the constructor.  It actually is a property of the prototype.

> 
>   Point.zero = function() { return new Point(0, 0); }
> 
>   Point.zero(); // "static" method.

 It's all a mater of how you think of responsibilities.  In a consistent prototype based usage, the "zero" point would probably actually be the prototypical point in which case you would access it simply as Pointl 


> 
> The second set of properties are properties on ".prototype" in JS: Its
> 
>   Point.prototype.flipX = function() {
>     this.x = -this.x;
>   }
> 
>   var p = new Point(1, 2);
>   p.flipX();
>   p.x // -1
> 
> To me, those two sets are utterly distinct. This code looks pretty strange:
> 
>   Point.flipX(); // What x?
The x of the prototypical point named Point.  As a prototypical point it has all the properties of any other point instance including an x and y property.
(I'm ignoring the fact the a point abstraction with mutable x and y fields is probably not a very good design).

In practice, you probably wouldn't call such a method on the prototype, so you wouldn't see the above at all.  But you could, that's what it means to be a prototype-based language.

> 
>   var p = new Point(1, 2);
>   p.zero(); // This works, but what does it have to do with 'p'?

probably as much as any other Point method that creates a new instance.  Since you probably really do want to have immutable points, that means most point methods:

  p.add(new Point(3,4)); //returns a new point with x=4, y=6
  p.zero();                          //return a point with x=0,y=0

But, similar to above, in practice you probably would seldom actually see the latter. You would just see:
  Point.zero();

> 
> Your proposal would allow that, I think. For example, starting from yours:
> 
>   // Superclass
>   var Person = {
>       constructor: function (name) {
>           this.name = name;
>       },
>       describe: function() {
>           return "Person called "+this.name;
>       }
>   };
> 
> I could do:
> 
>   var bob = new Person("Bob");
>   bob.constructor("Fred"); // I guess I'm Fred now.
> 
> Does the above seem strange to you too?

not particularly anymore so than
   Bob("Fred");    //note no new
or
   Bob.call(bob,"Fred")

Allen
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20110628/77c01361/attachment.html>


More information about the es-discuss mailing list