Minimalist Classes

Allen Wirfs-Brock allen at wirfs-brock.com
Tue Nov 1 12:35:27 PDT 2011


On Nov 1, 2011, at 11:04 AM, Jeremy Ashkenas wrote:

> I'm afraid that this super() discussion has gotten way off topic from the actual minimalist classes thread (which would be much more fun to talk about)

I agree and it's probably why I may sound slightly grumpy.  Dealing with super is not  a problem that we need to open up again.  We have a sound proposal that has already been throughly discussed.  This thread seems to be turning into a tutorial on the semantics of "super" in OO languages. I'd be happy to engage in that in another context but it is something that  we really don't need to do here. 


> -- but in the interest of dynamic class bodies, let's run it down.
> 
> On Tue, Nov 1, 2011 at 12:45 PM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
> 
> Jeremy, have  you looked at the current super proposal at http://wiki.ecmascript.org/doku.php?id=harmony:object_initialiser_super 
> 
> I hadn't looked at the current super proposal in great depth, but thanks for the link. 
>  
> It does not couple super use with classes at all.  It does make it easy to define a super referencing method in an object or class literal, but the mechanism of super can be applied to any method defined in any object. 
> 
> You are creating confusion by suggesting that the proposed ES6 super support "fails to work at all with regular prototypes".
> 
> Browsing through the examples on the page, the current super proposal *does* seem very coupled to "classes" ... by in this case being coupled to your proposed <| operator.

<| is also not coupled to "classes".  <| is probably best thought of as a restricted form of the non-standard __proto__ property.

> If you try to use the proposed super with current standard prototype patterns, this happens:
> 
> Fox.prototype.dig = function() {
>   super.dig();
> };

As described in http://wiki.ecmascript.org/doku.php?id=harmony:object_initialiser_super#imperatively_binding_super the proper way to do this is:

Object.defineMethod(Fox.prototype, "dig",  function() {
  super.dig();
});

Using the "mustache" operator it could be more concisely expressed as:

Fox.prototype.{dig () {
  super.dig();
};

Use of these forms is necessary for the "plan b" static binding of super. 

We possibly could redefine = to do the necessary rebinding.  It is something that I have considered.  However, it would introduces a number of issue.  To start it makes every property assignment more expensive because a check must be made to see if the RHS evaluates to a function that may require resupering.  It also would mean that sometimes property assignment does not preserve identity of the RHS value.  Also, there is no way to disguising the cases were a property (perhaps array elements) is just being use for data storage of a function (perhaps a bound function with a super reference) and the cases where a property is actually being used as a method and need to be resupered.  A number of these concerns also have backwards compat. issues with existing ES code. 


> 
> (new Fox).dig();
> TypeError: Object #<Object> has no method 'dig'
> 
> Likewise, for the other usual way of setting a prototype:
> 
> Fox.prototype = {
>   dig: function() {
>     super.dig();
>   }
> };
> 

This is already problematic because it yields a malformed  prototype object whose "constructor" property does not reference Fox.

As shown above .{ would be the property way to express this.  Constructs of the form you use here probably should be linted. 

> (new Fox).dig();
> TypeError: Object #<Object> has no method 'dig'



> 
> In the first case, the internal [[Super]] property is null. In the second case, the internal [[Super]] property is Object.prototype. Both cases will be quite frustrating for most JavaScript programmers.
> 
> Naturally, use of the <| operator instead of ".prototype" fixes this, but that coupling of the two syntaxes was the point I was trying to make. There is also Object.defineMethod() ... which would work for setting functions-that-use-super on a prototype imperatively, but that's far too verbose of a solution to propose for the common case. All that I'm trying to say is that the super() that JS.next adopts would do well to continue to work properly in the two examples above.

and that is one of the roles for .{ 

I think what we are seeing here are many of the reasons why designing ES.next is not nearly as simple and straightforward as some think it should be.  We have a currently primarily exposes a number of composible low level primitives for constructing objects.  User desire and we desire to provide higher level constructs  for defining abstractions over objects.  Those constructs need to be defined in terms of coordinated usage of the existing (and a few new) object construction primitive. However, the objects that are created still have to behave well when used in combination  with primitively constructed objects that don't necessarily maintain the invariants assumed by the new higher-level constructs.  In addition, we can't break any existing code and we want to make sure that usage of the new features can reasonably be added to existing code.

We don't have a clean slate and viable solultion have to make compromises from the ideal. 

> 
>  
> Just saying "I don't think that an efficient, pay-as-you-go dynamic super() will be easy, but with the technical chops of TC39 at your disposal, it should be possible" is not helpful, particular when you make other statement that suggest that you really don't understand all the semantic subtitles of super. I hate to cite "authority" but the semantics and implementation alternatives of super  has been thoroughly explored over 30+ years by object-oriented language designer and implementer including myself.  This is not a new problem, the "technical chops" have already been supplied.  A unique new solution that no one has ever though of before would be welcomed.  If you have such a solution, please put it forward.  But don't assume that it is something that has not already been deeperly consider both by TC39 member and other language designers.
> 
> I hear you loud and clear, and would only be too happy to get off your lawn ;) All that I can cite is an utter lack of authority, and little experience with even undergraduate computer science -- there are very few assumptions here on my part. That said, if ES-Discuss wants to be an open forum, sometimes the rabble gets to speak up and be ignorant.

I really welcome your participation, and would particular like to get back to talking about "classes".  You certainly belong here. Generally I don't mind "tutoring the rabble" (your term, not mine) but in this particularly case it is a distraction.


> 
> So, speaking from ignorance, here's a simple proof of concept in ES3 of how dynamic super calls can work with a little bit of metadata:
> 
> https://gist.github.com/1331310
> 
> ... which prints out:
> 
> In the GreatGrandParent.
> In the GrandParent.
> In the Parent.
> In the Child.
> 
> In a more ideal implementation, you'd use references to protos instead of counters, and your metadata would be scoped to be specific to an [object, methodName] pair ... but I think that this example is a bit clearer.
> 
> Hopefully this solution isn't unique or new, but dynamic languages are powerful things, and I would hope that dynamic super() is a pattern that's not logically impossible or inherently inefficient to implement, given a bit of extra bookkeeping behind the scenes.

To quick comments:

1) the problem with super start to occur when you have downward this calls (calls from a super accessed method that calls to via this to methods closer to the leaf of the prototype hierarchy).  This is where unintended loops can occur if you aren't aren't careful in your design.  I don't see your example exercise this use case.
2) maintaining state around the inner call is going to have the same sort of problem I pointed out about Demitry's proposal.

Allen


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20111101/f796f8ca/attachment-0001.html>


More information about the es-discuss mailing list