-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Can we use traits to establish the inheritance hierarchy when importing JS classes and interfaces? #152
Comments
Yeah this is a good point! I haven't thought much about how inheritance hierarchies will work and how it'll be modeled in Rust. I think there's some good precedent in other ecosystems, but I'd just want to take sme time to evaluate it to figure out the best way to tackle this. |
Fair enough. |
Oh sorry I'm actually totally fine leaving this issue open, just wanted to write down my current thoughts. This is definitely something I think that should be tracked and tackled! |
Ah cool. |
That's exactly what stdweb does. It has an This works out well in practice. I'm deeply involved in stdweb (both in its implementation and also using it for real projects), so I can give advice, and I'm totally interested in helping get wasm-bindgen up to parity with stdweb. |
Seems plausible to me! I'd be totally down for a sketch of what codegen may generate |
Am I correct that this issue is asking about importing and representing existing JS class hierarchies rather than creating new ones? I'm trying to figure out how to import a JS class, extend it in Rust, and export it to JS. |
@mruzekw correct! I think defining a Rust struct which "inherits" from a JS class would probably be a separate issue |
Talked with @alexcrichton about this a little yesterday. I think there are two separate axis involved with supporting bindings to JS things that have single inheritance relationships (not broaching cross language inheritance):
I think we can mostly design and implement these two things separately. |
@fitzgen For number 1, I am really quite fond of how Regarding number 2, one alternative the previous proposal of using a trait hierarchy like I personally found with |
@ohanar, deref doesn't actually work for (2). I think I didn't explain clearly enough. Consider the following example: Some JS: class Base {
method() { return 0; }
}
class Derived extends Base {
method() { return 1; }
} And some wasm-bindgen bindings to that JS: #[wasm_bindgen]
extern {
type Base;
#[wasm_bindgen(method)]
fn method(this: &Base) -> i32;
#[wasm_bindgen(extends = Base)]
type Derived;
#[wasm_bindgen(method)]
fn method(this: &Derived) -> i32;
} And a function that takes a fn call_method(b: &Base) -> i32 {
b.method()
} When we invoke The Rust equivalent, assuming we used traits to represent inheritance, would be |
@fitzgen Sure, I understand that, but I don't see how that problem exists in this context, at least for targeting WebIDL (which is our primary target here). I put together a playground with what I think you are suggesting for traits. I put a couple of comments in there, and I'm wondering if you have an example snippet of WebIDL that would result in producing unique code for The only bit from the WebIDL spec that I found mentioning how overriding members behave was the following:
And, at least how I read it, I don't see ever having a case where we can access an overridden method while we only have a reference to a base interface. |
Note: I'm just being cautious and exploring the problem space a bit. I'm certainly not trying to make strong statements that anything proposed thus far is fundamentally flawed or anything like that! Just thinking out loud a bit. First observation: inheritance is widespread in Web interfaces. Consider
Second observation: most of the methods one actually wants to use on The way we grab imported methods, we do All that said, I don't know how often methods get overridden in practice in Web APIs. I can't think of any off the top of my head. Some quick and dirty bash scripting shows that there are a bunch of duplicate method names, although I don't know whether there is inheritance and overriding involved in these:
Output
Yep, this is pretty much what I expect we will eventually do. However, I am not proposing anything yet because I don't think we've fully explored the design space yet.
I'm not sure I understand what you mean by "producing unique code". In general, I'm not worried about the code emitted by To move forward, I think we can do two orthogonal things:
|
RFC for defining single inheritance relationships, upcasting, and downcasting: rustwasm/rfcs#2 (aka bullet (1) from my last comment) |
Data! Boriz Zbarsky very kindly hacked up Firefox's WebIDL code generator to dump information about overrides. Here is what he passed along to me:
Some notes about exclusions:
Excluded because static methods/attributes don't really suffer the same issues with overrides due to the way they are invoked.
These are situations where: interface ReadOnlyThing {
readonly attribute long x;
}
interface Thing : ReadOnlyThing {
// this property receives the exact same getter as ReadOnlyThing, but _also_ a setter
inherit attribute long x;
} Excluded because it doesn't seem footgun-able either. Digging into the overrides that do exist.
This is pretty terrifying from an API design perspective. The select method returns a completely different type than the element method. I think these are logically two different functions that happen to share a name and are on interfaces that inherit from each other, and are accidentally an override.
I think we can safely ignore
These toJSON methods extend the emitted JSON to have more specific information when more specific overrides are used. Not the end of the world if the wrong one is used.
These methods have completely different parameter sets :( Overall, it seems like there are a few cases where calling the base method with a derived thing is going to be a foot gun, but it's not common. I think we can basically stop worrying too much about this for the most part. |
Nice investigation! I'd reach a similar conclusion too :) |
With rustwasm/rfcs#2 now in FCP I'm gonna close this in favor of that RFC, any more discussion should definitely happen there! |
For example in the DOM API, 'Node is an interface from which a number of DOM API object types inherit'(from MDN docs). Now there is no way in
wasm-bindgen
yet to specify such a relationship between imported types (as far as I know), which leads to lot of repeated codes when trying to import inherited methods for two separate types.The text was updated successfully, but these errors were encountered: