On May 31, 2012, at 10:57 PM, Luke Hoban wrote:

> On May 31, 2012, at 1:54 PM, Allen Wirfs-Brock wrote:
> 
>> On May 31, 2012, at 1:53 AM, Herby Vojčík wrote:
> 
>>> Hello,
>>> 
>>> reacting to "super only in classes", I'd like to propose widening it just a 
>>> little bit:
>>> 
>>> 1. Allow super in every concise methods (in classes, as well as out of 
>>> them).
> 
>> Basically this means in object literals (or object extension literals if we 
>> have them)
> 
> It still seems to me that the majority of the time, super used in an object 
> literal will not actually behave correctly.  My pushback on a general notion 
> of super outside of classes is based on the assumption that it will be a 
> misleading feature, suggesting support for super calls in many places there 
> actually is not.  
> 
> In fact, without <|, are there any cases where super behaves correctly in an 
> object literal, other than making super calls to Object.prototype functions?

We haven't eliminated the ability to define object literals that inherit from 
objects other than Object.prototype.  We have just changed the syntax for 
specifying them from:
   proto <| {}
to
   {__proto__: proto}

In general, if you have multiple level instance based inheritance hierarchies, 
super has the same general utility that it has in an a class/instance based 
inheritance hierarchy. 

> 
> Take Backbone/Underscore as an example.  A developer writes some code like:
> 
> var Note = Backbone.Model.extend({
>    set: function(attributes, options) {
>        super.set(attributes, options);
>    }
> });

Of course, the above is a case where I suggest a mustache should probably be 
used.  If extend did not explicitly deal with rebinding super referencing 
methods (which it can't, if we eliminate defineMethod) then the set method 
would throw when it tried to invoke the super.set.  So, the code fails with an 
exception rather than silently working incorrectly.

Also, a very similar issue will apply to if the argument to extend had any 
private name properties.  So this isn't a problem that is specific to super. I 
can actually envision how it may be easier for a built-in extend function to 
handle super rebinding than it would be for it to handle private names.  I 
don't currently see how a non-built-in Es<=5 semantics based extend could 
handle it.

The issue of passing new semantic constructors into legacy frameworks is 
certainly worth thinking about.  Although, i tend to think that actively 
maintain frameworks will get ahead of the ES6 adoption curve.  And that legacy 
using a out of date framework is much less likely to start using new ES6 
constructs.

> 
> They rightly think they can use a super call inside an object literal.   But 
> it doesn't behave correctly, because extend is ultimately (somewhere in code 
> that the end-developer shouldn't really need to be aware of) implemented in 
> just the simple ES3-compatible way:
> 
>  _.extend = function(obj) {
>    each(slice.call(arguments, 1), function(source) {
>      for (var prop in source) {
>        obj[prop] = source[prop];
>      }
>    });
>    return obj;
>  };
> 

Of course, the above doesn't even work for ES5 since it it ignores 
non-enumerable properties, doesn't copy accessor properties correctly, and 
probably unintentionally includes inherited properties. We should be cherry 
picking super as the only feature that is problematic for such code.

One might speculate if these deficiencies aren't causing problems today, then 
perhaps the issue of passing new language constructs into to legacy frameworks 
that don't correctly deal with them is not a significant problem.

> As I understand it, super will not work correctly in cases like these unless 
> the authors of every object model library opt in to taking an ES6 dependency 
> on Object.defineMethod, or fork their implementations to detect and behave 
> differently on ES6.  I believe the necessary change to these APIs is intended 
> to be something like this - but I'm pretty sure this also wouldn't be 
> correct, because it rebinds the super bindings of functions which may have 
> been correctly bound previously to other points in the prototype hierarchy. 
> 
>  _.extend = function(obj) {
>    each(slice.call(arguments, 1), function(source) {
>      for (var prop in source) {
>        if(typeof prop === 'function') {
>          Object.defineMethod(obj, prop, source[prop]);
>        } else {
>          obj[prop] = source[prop];
>        }
>      }
>    });
>    return obj;
>  };\
Basically, except I would only want to rebind the function if the current 
function is bound to the object it is being extracted from.
> 
> Basically - I just don't see that this feature can be made to feel like it 
> "just works", in a practical sense, outside of classes.

But also note that class instance or class prototype objects can be used in all 
the same situations where you have used object literals.  Nothing here is 
unique about their occurrence in object literals.  

Here is another way to think about this class of issues. super is a language 
feature that is design to work at the level of the built-in behavior 
composition mechanism of ES (a fixed single inheritance [[Prototype]] chain).  
_extend and other abstraction impose a different behavioral composition model.  
super may not work as expected with those other models unless their 
implementation takes it input account in their implementation.

Thanks, for these issue.  They are good ones.

Allen


> 
> Luke
> 

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

Reply via email to