Skip to content

Replace traits with Deref #293

Open
Open
@Pauan

Description

@Pauan

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 use fn 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions