Description
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 the Deref
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:
fn foo<A: IFoo>(x: &A) { ... } fn foo(x: &Foo) { ... }
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 a Bar
or Qux
(they might think it only accepts a Foo
). 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:
#[reference(child_of = Foo)]
struct Bar( Reference );
That will generate this code:
impl Deref for Bar {
type Target = Foo;
#[inline]
fn deref( &self ) -> &Self::Target {
let reference: &::stdweb::Reference = self.as_ref();
unsafe {
<Self as ::stdweb::ReferenceType>::from_reference_unchecked_ref( reference )
}
}
}
(This also requires adding a new unsafe fn from_reference_unchecked_ref( reference: &Reference ) -> &Self;
method on ReferenceType
)
Root classes should have #[reference(child_of = Object)]
, and Object
should probably have #[reference(child_of = Reference)]
(should Reference
have #[reference(child_of = Value)]
?)
We should also change subclass_of
so that it generates AsRef<Foo>
implementations, so that way it's still possible to use AsRef<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.