-
Notifications
You must be signed in to change notification settings - Fork 178
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
Replace traits with Deref #293
Comments
Alternatively, we could have a system where sub-classes don't contain a #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Foo")]
struct Foo( Reference );
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Bar")]
#[reference(subclass_of(Foo))]
#[reference(child_of = Foo)]
struct Bar( Foo );
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Qux")]
#[reference(subclass_of(Foo, Bar))]
#[reference(child_of = Bar)]
struct Qux( Bar ); This makes it possible to convert from a |
I wonder, if this should be considered separately from or combined with the long term goal of making stdweb compatible to (or building stdweb upon)
, but shys away from introducing strong dependencies like inheriting from |
@NeverGivinUp It's both. The long-term goal of compatibility with wasm-bindgen will require a lot of changes (including breaking changes). It will take a long time and a lot of work. So it must be done incrementally, in small chunks. This is one of those chunks. And it can be implemented independently of the other chunks. Also, this change to
That's a very big change, requiring a dependency on wasm-bindgen and js-sys. Right now it's not even possible to combine stdweb and wasm-bindgen in the same Rust project, so that's not a feasible change right now (though it is the long-term goal).
Of course it's different from wasm-bindgen: it's the same system that stdweb uses right now (except with It's not a second proposition, it's describing a small implementation detail (as an alternative to using The user API is the same either way (in both cases it uses |
Thanks a lot for clarifying @Pauan. Very helpful, as always (: Obviously I didn't know what needs do be done for wasm-bindgen-compatibility and how this fits in the grand scheme of things. Is there a list of tasks? |
I don't think so, and it's a bit hard to make such a list, since we're not even sure what all the incompatibilities are. As a first step, wasm-bindgen will need to support some sort of After that it will be a matter of replacing stdweb's runtime with wasm-bindgen's runtime, replacing Plus various other changes that will need to happen to cargo-web (which I'm not very familiar with). It's basically a full rewrite of stdweb from the ground up. This is because the underlying philosophy, implementation, and APIs are very different between wasm-bindgen and stdweb. |
Thanks for the proposal @Pauan! Hmm... I would probably be fine with this, however it does make me somewhat uneasy that this wouldn't support multiple interfaces/mixins (as It also feels like the current trait based system is more Rust-y. Many people do think that using
So it's a little surprising to me that a That said, while I probably like trait based system more as it feels more Rust-y and is more flexible, I don't have super strong opinions that it's objectively better, although it does feel to me like it is. You're right that if we do this it'd be the best to do this progressively. Perhaps instead of adding
As Pauan said, there isn't. However I would envision roughly something like this:
|
That's a good point, I should have addressed that in my original post. The simple fact is that JavaScript doesn't support multiple interfaces/mixins, it only has single inheritance. The interfaces and mixins in the WebIDL spec are purely for the editor's convenience, in actuality the methods will be duplicated in JavaScript. It sucks to generate duplicate methods in Rust (though macros can help with that), but it is the more semantically precise thing to do. Long term, once stdweb is using
I agree! But that doesn't change the inherent disadvantages of traits (and advantages of I think that the advice of avoiding Also keep in mind that generic situations will use
I'll be honest, I was surprised as well. At first most people were on board with traits (with Alex being the only real exception). But after I carefully and thoroughly documented all the pros and cons of traits vs Deref (and as some people pointed out some use cases I hadn't considered), I slowly came to the realization that Deref is probably better. It wasn't an easy realization for me to make, and I'm still not 100% sold on it, but it's probably the best option we have (until Rust gets a proper inheritance mechanism).
That idea seems quite reasonable. I'll try some experiments to see whether the I think a good first step is to add in a Assuming that works out, then we can enable the Also, I'd like to note that it is possible to have both traits and |
Sounds good to me! |
Just a heads up that the |
It's worth reading the discussion thread for Deref RFC, it goes through quite a lot of the advantages/disadvantages of each approach. |
I had created an RFC for adding in traits to wasm-bindgen (similar to what stdweb is doing), however it has been superseded by an RFC which uses
Deref
instead. It is highly likely that theDeref
RFC will win.Although I was the biggest proponent for stdweb-style traits (and I still think it's a solid system), I've since come around to
Deref
, it has several advantages that traits don't have:It is much simpler to implement, and simpler to use (no need to import traits, no need to use generics).
It doesn't cause monomorphization bloat, because it's not using generics.
With traits you have to choose between these two styles:
There are various trade-offs between these two styles, which makes it difficult to choose.
But with
Deref
, you just always usefn foo(x: &Foo) { ... }
, and it will always have the correct behavior.Within the documentation it lists all of the methods that the type supports (right now most of the methods are implemented within traits, so they're not obviously visible in the docs).
(There are some downsides as well, such as that users might not realize that a function/method which accepts a
Foo
also accepts aBar
orQux
(they might think it only accepts aFoo
). This can largely be solved with solid documentation.)For the sake of gaining those advantages, and also for more consistency with the wasm-bindgen ecosystem, I think we should replace our traits-based system with a
Deref
-based system.We will need a new attribute which generates the
Deref
implementation, something like this:That will generate this code:
(This also requires adding a new
unsafe fn from_reference_unchecked_ref( reference: &Reference ) -> &Self;
method onReferenceType
)Root classes should have
#[reference(child_of = Object)]
, andObject
should probably have#[reference(child_of = Reference)]
(shouldReference
have#[reference(child_of = Value)]
?)We should also change
subclass_of
so that it generatesAsRef<Foo>
implementations, so that way it's still possible to useAsRef<Foo>
in generics.We will also need a migration path: first we add in
Deref
and deprecate traits, and then in the next major release we remove the traits.I'm willing to make a PR that does all of that. But we should wait until the
Deref
RFC is accepted and implemented in wasm-bindgen.The text was updated successfully, but these errors were encountered: