-
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
[CS2] Bound methods are unsafe to use with inheritance #4497
Comments
I'd like to throw in a 4th option:
The use-case for them is pretty small, and the behaviour is very implicit and has a lot of caveats. Explicitly binding methods at call time or in a constructor makes things much easier to follow, and lets users choose their own tradeoffs. |
If they're not supported in ES classes, I vote for removing them. |
They're sort of supported through public class properties, for example. The proposal itself is here. In general such properties cannot currently be represented in CoffeeScript, and the syntax conflicts with executable class bodies: class Foo
a = 1 # this is a plain assignment in the class body scope, not a public property initialiser
a: 1 # this is a prototype assignment, not a public initialiser
@a = 1 # this is an assignment to the class, equivalent to a public static property
a: => # this is the closest thing we have to a public class property, as method is assigned in
# the constructor |
That proposal is only stage 2. I say we don’t support them until they release stage 4, but don’t paint ourselves into a corner by precluding what the likely supported syntax would be. |
Yeah, it's still binding |
@Iluchs do you mind explaining what the current behavior's caveats are? The current behavior since #4526 I mean, my example above. I'm thinking, rather than ban bound methods entirely and force a somewhat large breaking change, if we can detect the specific scenarios that are problematic we can throw errors in those cases. For example, calling |
Just as I explained in the original issue text: if the super constructor tries to use a bound function, it will get the unbound one from the prototype. I don't think it's possible to detect this statically as it depends on the super constructor's code. |
So is this unwanted behavior serious enough that we should ban bound methods in classes? It seems like we don't have any other options? |
Yeah, it's a silent but major incompatibility with CS1. I think having a clear "bound methods aren't supported anymore" message makes upgrading easier than having to find all now-invalid uses of bound methods through testing. Additionally, I feel like bound methods as in CS2 go against the CoffeeScript idea of "JS without the hard parts" by introducing a feature with tricky semantics which are easy to get wrong. |
This will likely irk plenty of people using classes with Backbone/React/other frontend frameworks where they want to pass around bound event handlers. This has come up and been dropped before (#2136 and others), but perhaps we should switch to a lightweight 'binding access' operator, something like Edit: turns out I've brought this up before 😅 |
So what do you propose? Only throwing an error when bound methods are used on a class that also Or just take out bound methods entirely, and when the proposal reaches Stage 4, we add them back again and compile to ES public class properties? |
I've opened #4530 to show the changes for removing them and highlight the alternatives discussed here. Personally I think removing them would be the best option, but I've always had a bit of a prejudice against bound methods so I'm not the most objective 😅 |
What error would be thrown if a parent class called var SomeView;
SomeView = class SomeView extends Backbone.View {
constructor() {
super(...arguments);
this.onRender = (options) => {}
}
}; |
That would throw a The problem with CS' implementation of bound methods is that |
Wouldn't it be odd for a parent class to call a method it didn't itself have? Like if it calls So if it's safe to assume the parent class has all the method it calls in its constructor, and it should if it wants to be instantiated by itself ever and not just extended, then the issue is really that it's calling it's own versions on initialization and the child's versions thereafter. I guess the question is how bad that would be. |
Resolved in #4530. |
Bound methods are now only bound after calling the super constructor. If the super constructor calls any methods in the class, you end up with unbound references to functions.
Example:
While it's not possible to bind the functions before calling the super constructor, there are some ways CS2 could make bound methods "safer" to use. Some ideas:
@callback
would always compile tothis.callback.bind(this)
. While this solves the issue for local uses, it doesn't help for external access.this
. Doesn't solve the issue, but would make errors like in the example above more visible. Would need additional thought to avoid naming conflicts and for interaction with non-CoffeeScript classes in the inheritance chain.Related issue #4239 still stands, but now it's also an issue for the base class.
The text was updated successfully, but these errors were encountered: