---
title: "Arbitrary self types options"
tags: ["T-lang"]
date: 2024-02-28
discussion: https://rust-lang.zulipchat.com/#narrow/stream/410673-t-lang.2Fmeetings/topic/Design.20meeting.202024-02-28
url: https://hackmd.io/eXfrzrR7T1-3HVh6w5JMqA
---
# Arbitrary self types options
## Constraints and goals
* We want to permit adding additional methods to `*mut T`.
* Requires: libs team is able to add methods without disruption to the ecosystem or existing programs.
* We want to permit adding `self: MyRc<T>` methods.
* We need code to continue compiling, with same semantics, in rustc vN and vN+1.
* We need `trait Receiver` separate from `Deref` because not all smart pointer types can support deref (for good reasons).
* We need a way to define methods that do not form a (safe) Rust reference when called.
* We need to be forward-compatible with ways to invoke through `dyn` (not covered in the RFC).
## All options
* Uses `Receiver` trait to identify method candidates. This allows `fn foo(self: P<Self>)` for custom smart pointers.
* Blanket impl of `Receiver` for `T: Deref`.
## Option 0: Support for newtype wrappers, no changes to resolution order, methods prohibited by convention alone
* Use the current outer-first resolution order, i.e. prefer `Box::foo(self)` over `fn foo(self: Box<Self>)`
* Largely resolves the needs of Rust-for-Linux (`KernelArc<T>`) and cross-language interop (`CppRef<T>`).
* Possibility to define a wrapper `Raw<T>: Receiver` in core to cover the unsafe Rust use-case.
* New methods on an outer type (e.g. `Box`) run the risk of shadowing existing methods on an inner type. Anyone implementing `Deref` or `Receiver` should not add methods, just like we don't add methods for `Box` and friends. But this is not enforced.
* Believed to be forward-compatible with options 4 and 5.
## Option 1: Support for newtype wrappers, with "inner-first" resolution order
* Use an inner-first resolution order, i.e. prefer `fn foo(self: Box<Self>)` over a `foo` method defined on `Box<T>`.
* Largely resolves the needs of Rust-for-Linux (`KernelArc<T>`) and cross-language interop (`CppRef<T>`).
* Possibility to define a wrapper `Raw<T>: Receiver` in core to cover the unsafe Rust use-case.
* Not forward-compatible with options 4 or 5.
## Option 2: Support for newtype wrappers, with a hard error on resolution ambiguity
* Method resolution gives an error when there is ambiguity between a `Receiver`-resolved method like `fn foo(P<Self>)` and some other method.
* Largely resolves the needs of Rust-for-Linux (`KernelArc<T>`) and cross-language interop (`CppRef<T>`).
* Possibility to define a wrapper `Raw<T>: Receiver` in core to cover the unsafe Rust use-case.
* Similar to current behavior (option 0), but we'd probably error on a couple more cases where we currently pick either the outer or inner (we always prioritize by-value calls over by-reference calls).
* Believed to be forward-compatible with options 4 and 5.
## Option 3: Support for raw pointers, do not allow new methods on raw pointers
* Option 0, 1 or 2, with the addition that we make `*mut T` (and probably `NonNull<T>` and `Weak<T>`) implement `Receiver`.
* Supports the use-cases in unsafe Rust, as well as RfL and cross-language interop.
* We decide never to add new methods to raw pointers, `NonNull` or `Weak` again.
## Option 4: Support for raw pointers, add new method resolution rules with a warning
* In case of a method resolution ambiguity involving a `P<Self>` method, we pick the method defined on the inner type and show a warning.
* Make `*mut T` (and probably `NonNull<T>` and `Weak<T>`) implement `Receiver`.
* Supports the use-cases of unsafe Rust, as well as RfL and cross-language interop.
* This permits us to add new methods to raw pointers, `NonNull` and `Weak` though this would still require users to resolve warnings so we might still not want to.
* This can still cause surprises (in the "race condition" scenario explained below) since warnings are suppressed when compiling a downstream crate.
## Option 5: Support for raw pointers, add new method resolution rules with no warnings
* In case of a method resolution ambiguity involving a `P<Self>` method, we silently pick the the method defined on the inner type.
* Make `*mut T` (and probably `NonNull<T>` and `Weak<T>`) implement `Receiver`.
* Supports the use-cases of unsafe Rust, as well as RfL and cross-language interop.
* This permits us to add new methods to raw pointers, `NonNull` and `Weak`.
* This can silently change which method is called if a crate defines `fn foo(self: NewBox<MyType>)` while in parallel the crate that defines `MyBox` adds a `foo` method (the "race condition" scenario).