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