Do we stabilize `Receiver` now or wait for `#[derive(SmartPointer)]`? ## The decision Do we: * Stabilize a `Receiver` trait, without any special support for dynamic dispatch, allowing us to add more traits later for types which wish to support dynamic dispatch * _Instead_ stabilize `#[derive(SmartPointer)]`, which currently might only `impl Receiver` but in future will also implement `DispatchFromDyn` (or whatever else is required to support dynamic dispatch). If we're sure that we'll always want smart pointers to `#[derive(SmartPointer)]`, then we can reduce our future compatibility burden by not exposing `Receiver` additionally. ## Related material * [`DispatchFromDyn`](https://doc.rust-lang.org/std/ops/trait.DispatchFromDyn.html) * Arbitrary self types [design meeting minutes](https://hackmd.io/@rust-lang-team/rk2biy6n6) * Notes on the RfL [needs](https://hackmd.io/@rust-lang-team/HymfJSLa6) and specifically on the [rationale for why this derive might be good](https://hackmd.io/@rust-lang-team/HymfJSLa6#Will-the-deriveSmartPointer-proposal-work-for-Rust-for-Linux) * [RFC/minutes for this new `#derive`](https://hackmd.io/@rust-lang-team/HyYXScDa6) ## Questions * Are there any use-cases for smart pointers where we would not want dynamic dispatch? * Are there any types which might want to implement `Receiver` which are not smart pointers? If the answer to either of these is "yes" then that's a definite reason to allow direct `impl` of `Receiver` instead of wrapping it up into`#[derive(SmartPointer)]`. ## C++ dynamic dispatch use-cases Summary: `DispatchFromDyn` is harmless but probably not useful, and might be confusing. It would be better if we could implement `Receiver` without `DispatchFromDyn.` Details: Imagine we have: ```cpp class Base { public: virtual void Method() const; }; class Derived : public Base { public: virtual void Method() const; }; ``` We would like to be able to call that in Rust like this: ```rust fn some_function() { let cpp_ptr: CppPtr<Base> = obtain_from_cpp(); cpp_ptr.Method(); // may call Base::Method or Derived::Method } ``` We couldn't use trait objects for this. It seems more likely that we'd want to call into some C++ shim function which does the dynamic dispatch according to C++'s precise vtable rules. (Cross-language inlining should make this free of overhead). Most likely, the shim would look something like this: ```cpp void CallBaseMethod(const Base* b) { b->Method(); } ``` I am confident we would not use trait objects for C++ dispatch. Are they actively harmful? Not really, but having two types of dynamic dispatch here might be confusing. ## Rust for Linux usecases Summary: there are some types which want to implement `Receiver` and _definitely cannot_ implement `DispatchFromDyn`. Details: Rust for Linux has at least one type where they _do_ want to implement `Receiver` but do not and _cannot_ implement `DispatchFromDyn`: This is the [`Wrapper` type described here](https://rust-for-linux.com/arc-in-the-linux-kernel#nextprev-pointers-and-dynamic-dispatch): ```rust struct Wrapper<T: ?Sized> { next: *mut Wrapper<T>, prev: *mut Wrapper<T>, value: T, } ``` This isn't actually a _pointer_ so can't support dynamic dispatch. ## Conclusion We must allow implementation of `Receiver` without implementing `DispatchFromDyn`, and therefore we should proceed with exposing `Receiver` intead of wrapping them up together into `#[derive(SmartPointer)]`.