-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
What should super
refer to?
#3796
Comments
Totally agreed. I also find it very inelegant that # Extracting the prototype into a variable doesn't work:
proto = A.prototype
proto.foo = -> super # Error
# Nor does using a function to assign the methods to the prototype:
_.extend A.prototype,
method: -> super # Error That being said, however, couldn't we make // For `expr().method = -> super`
var _ref, _super;
_super = (_ref = expr()).method
_ref.method = function() {
_super.apply(this, arguments)
};
// For the more general `expr1()[expr2()] = -> super` case:
var _ref1, _ref2, _super;
_super = (_ref1 = expr1())[_ref2 = expr2()];
_ref1[_ref2] = function() {
_super.apply(this, arguments)
}; |
That will probably raise a"TypeError: Cannot call method 'apply' of undefined", wouldn't it? Edit: Just checked, it does. |
@lydell, this is a little example of what i meant: http://jsfiddle.net/18nqo06h/ // class A
// foo: -> console.log 42
var A = function() {};
A.prototype.foo = function() { console.log(42); }
// class B extends A
var B = function() {};
B.prototype = new A;
var f = function() { return B.prototype; };
var g = function() { return 'foo'; };
// f()[g()] = -> super
var _ref1, _ref2, _super;
_super = (_ref1 = f())[_ref2 = g()];
_ref1[_ref2] = function() {
return _super.apply(this, arguments)
};
new B().foo() // 42 It has its caveats though. For instance, if |
Now I understand. Clever! |
I now realize that it is still a very limited solution: # Assigning the super-calling function to a variable wouldn't work:
f = -> super
A::method = f
# Nor would using a super-calling function as a method on a literal object:
_.extend A.prototype,
method: -> super So, yes, i would vote in favour of limiting the Does ES6 allow Does this "work" in ES6? var a = {
foo() { super() }
};
Object.setPrototypeOf(a, {
foo() { console.log(42); }
});
a.foo() // 42? (It does not compile on 6to5.org, but i don't know if that's per spec or not; something similar using a class does work) |
Is there anyone who is a pro at searching Github and could back up this? If so, the decision to limit super to this case would be easier. |
Looking through the first ten pages as well as a few of the last and a bunch in the middle of those search results, I found one occasion where super wasn't used like above, but that one was a mistake by the developer. |
In general the current idea is to mostly limit Can you fill me in on exactly what situations we would lose support for if we followed @lydell's "keep it simple" suggestion? |
The following uses of class A
m: -> super # missing `extends`
@m: -> super # ditto
@::m = -> super # regular assignment not allowed
@m = -> super # ditto
A::m = -> super # ditto
A.prototype.m = -> super # ditto This is would continue to be allowed: class A extends B
m: -> super
@m: -> super Edit: Since #3785 has been merged the new cases allowed by that PR would become parse errors, too. |
And that would allow us to remove the |
Yep (see the beginning of the first post). |
I'm very tempted — so much so that I started typing out a "go for it" response before changing my mind — but I don't think that we should make that change. The main reason is this case:
... and then later, in another file, say
Removing the |
Why not write A::method = ->
B::method.call this
... continue refining method ... in that case? Besides, have you ever done that, or seen anyone do it? |
Because you don't want to have to know or think about what the name of the superclass happens to be. It could even be a value that's set at runtime in the other class, and you can't know what the name is. (Contrived, but possible.) I haven't ever done that, but I don't write much class-based CoffeeScript ;) |
What about this then? (Inspired by @epidemian above.) superMethod = A::method
A::method = ->
superMethod.call this
... continue refining method ... Pretty nice, eh? But anyway, I can’t believe that you argue for keeping the current somewhat odd semantics to support a non-use case! :) |
JavaScript has one |
I know that
super
has been discussed many times before (#2638 and #3436 for example), but in my opinion this is something new. This issue is not about changingsuper
totally, but merely about defining its edge cases. The reason I started this discussion is because of issues I bumped into when making #3785.This issue is not about what
super
without parentheses should do etc. It is only about whatsuper
should refer to in different cases.The only way I’ve ever used
super
, and the only way I’ve even seensuper
be used, is like this:That is, only in an instance method defined using the
method:
syntax inside aclass
body withextends
.If that was the only case
super
was allowed, compiling it would be trivial. The above could compile to:CoffeeScript also allows
super
in “static” methods:That would also be easy to compile:
If dynamic keys are implemented, that’d be straightforward too:
So far so good. All nice and simple.
CoffeeScript also allows a “classic” style for making “classes”:
Note that the above isn’t equivalent to the
class
examples, since the constructorA
doesn’t applyB
. That could be done by writingA = -> B.apply this, arguments
manually, but it would be much nicer to be able to writeA = -> super
, but that throws an error.There is no way to make a static method call
super
using the “classic” style.A.method = -> super
throws an error.So when is it possible to use
super
“classic” style?According to #1392 you should be able to namespace classes (properly implemented in #3785):
So what’s the problem? First of all, we don’t know the superclass, unlike in the
class
examples above. Therefore, the superclass is assumed to be accessible atA.__super__
.A
: Could be compiled to useA.__super__.constructor
.A.m
: Could be compiled to useA.__super__.constructor.m
.A::m
,A.prototype.m
: No problems. If we allow the above though, it might be confusing thatsuper
refers to different things inA.Prototype.m
andA.prototype.m
.A["prototype"].m
: IfA.prototype.m
is allowed, shouldn’t this also be? Ok, we could do it.A["pro" + "type"].m
: IfA["prototype"].m
is allowed, shouldn’t this also be? Ough, I see where this is going.A[prototype].m
: IfA["prototype"].m
is allowed, I’d expect this to be allowed, too. However, we don’t know ifprototype is "prototype"
.A[f()].m=->super
could compile to:But perhaps that single-time runtime check is a bit weird. Also it feels odd that
A[f()].m=->super
does different things tosuper
depending on the value off()
. Therefore it might be better to compile it to assume that it always means a definition of a static method. I mean, why would you ever use something else thanA::m
orA.prototype.m
if you really wanted to create an instance method? There’s no reason to.But even if
A[b].m
always meant static method, shouldA["prototype"].m
too? What aboutA["pro" + "type"].m
?There’s also the case where
super
is used in an object literal:However, why use an
extend
library function when you’re using CoffeeScript and haveextends
? And shouldn’t thatextend
function also provide some alternative tosuper
? So I guess this case should be disallowed, just like[1, (-> super), 2]
is.Summing up, this is what I think:
The
A.__super__
thing is ugly.super
is not “classic”: It does not belong to the “classic” style of making classes. If you’re using the classic style you’re not usingsuper
—instead, you might use some manual/“classic” way of doing it.So in my opinion,
super
should only be allowed in a function after amethod:
or@method:
in aclass
body. Nowhere else. That’s where they belong, and that’s where they’re simple. That’s also the only place I’ve ever seen them used. Compile it like the first two examples. Keep it simple! And as far as I understand,super
will only be available inclass
blocks in ES6 (I might be wrong, though).If that proposal is not acceptable, I’d say that
super
should refer to:Oh, and if anyone brings up ES6
super
, as far as I understandsuper()
calls the method with the same name of the superclass, whilesuper.anySuperMethod()
calls “anySuperMethod” of the superclass.What are people’s thoughts?
The text was updated successfully, but these errors were encountered: