Skip to content

Commit 8f760cb

Browse files
authored
Merge pull request #1 from ferrous-systems/attempt-1
First attempt to flesh out motivation and guide-level explaination
2 parents 4195b93 + ff94b4e commit 8f760cb

File tree

1 file changed

+48
-15
lines changed

1 file changed

+48
-15
lines changed

text/0000-stabilize-arbitrary-self-types.md

+48-15
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,24 @@
1-
- Feature Name: Stabilize Arbitray Self Types
1+
- Feature Name: Arbitray Self Types 2.0
22
- Start Date: 2023-05-04
33
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
44
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)
55

66
# Summary
77
[summary]: #summary
88

9-
Stabilize the existing unstable "arbitrary self types" feature.
9+
Allow types that implement the new `trait Receiver<Target=Self>` to be the receiver of a method.
1010

1111
# Motivation
1212
[motivation]: #motivation
1313

14-
Sometimes, Rust reference semantics are not right for the job. This is most commonly in cross-language interop (JavaScript, Python, C++), where other languages' equivalents can’t guarantee the aliasing semantics required of a Rust reference. Another case is when the existence of a reference to a thing is, itself, meaningful — for example, reference counting, or if relayout of a UI should occur each time a mutable reference ceases to exist.
14+
Today, methods can only be received by value, by reference, by mutable reference, or by one of a few blessed smart pointer types from `libstd` (`Arc<Self>`, `Box<Self>`, `Pin<Self>` and `Rc<Self>`).
15+
This has always intended to be generalized to support any kind of pointer, such as an `MyPtr<Self>`. Since late 2017, it has been available on nightly under the `arbitrary_self_types` feature for types that implement `Deref<Target=Self>`.
1516

16-
All of these use-cases are possible using some user-defined smart pointer type in Rust, wrapping an underlying raw pointer. That's what `Rc`, `Arc`, `Box` and `Pin` do in Rust’s standard library.
17+
Because different kinds of "smart pointers" can constrain the semantics in non trivial ways, traits can rely on certain assumptions about the receiver of their method. Just implementing the trait *for* a smart pointer doesn't allow that kind of reliance.
1718

18-
In theory, users can define their own smart pointers. In practice, they're second-class citizens compared to the smart pointers in Rust's standard library. User-defined smart pointers to `T` can accept method calls only if the receiver (`self`) type is `&T` or `&mut T`, which causes us to run right into the "reference semantics are not right" problem that we were trying to avoid. Conversely, the Rust standard library pointers (`Pin`, `Box`, `Rc` and `Arc`) are specially privileged by rustc as allowable receiver types.
19+
One relevant use-case is cross-language interop (JavaScript, Python, C++), where other languages' equivalents can’t guarantee the aliasing semantics required of a Rust reference. Another case is when the existence of a reference to a thing is, itself, meaningful — for example, reference counting, or if relayout of a UI should occur each time a mutable reference ceases to exist.
1920

20-
This restriction prevents custom smart pointer types where methods must be callable, but the existence of a `&T`/`&mut T` is not allowable.
21+
In theory, users can define their own smart pointers. In practice, they're second-class citizens compared to the smart pointers in Rust's standard library. User-defined smart pointers to `T` can accept method calls only if the receiver (`self`) type is `&T` or `&mut T`, which causes us to run right into the "reference semantics are not right" problem that we were trying to avoid.
2122

2223
This RFC proposes to loosen this restriction to allow custom smart pointer types to be accepted as a `self` type just like for the standard library types.
2324

@@ -26,18 +27,50 @@ See also [this blog post](https://medium.com/@adetaylor/the-case-for-stabilizing
2627
# Guide-level explanation
2728
[guide-level-explanation]: #guide-level-explanation
2829

29-
TODO
30+
When declaring a method, users can declare the type of the `self` receiver to be any type `T` where `T: Receiver<Target = Self>`.
31+
32+
The `Receiver` trait is simple and only requires to specify the `Target` type to be resolved to:
33+
34+
```rust
35+
trait Receiver {
36+
type Target: ?Sized;
37+
}
38+
```
39+
40+
Shorthand exists, so that `self` with no ascription is of type `Self`, `&self` is of type `&Self` and `&mut self` is of type `&mut Self`. All of the following self types are valid:
41+
42+
```rust
43+
trait Foo {
44+
fn by_value(self: Self);
45+
fn by_ref(self: &Self);
46+
fn by_ref_mut(self: &mut Self);
47+
fn by_box(self: Box<Self>);
48+
fn by_rc(self: Rc<Self>);
49+
fn by_custom_ptr(self: CustomPtr<Self>);
50+
}
51+
52+
struct CustomPtr<T>(Box<T>);
53+
54+
impl<T> Receiver for CustomPtr<T> {
55+
type Target = T;
56+
}
57+
```
58+
59+
## Recursive arbitrary receivers
60+
61+
Receivers are recursive and therefore allowed to be nested. If type `T` implements `Receiver<Target=U>`, and type `U` implements `Deref<Target=Self>`, `T` is a valid receiver (and so on outward).
62+
63+
For example, this self type is valid:
3064

31-
Explain the proposal as if it was already included in the language and you were teaching it to another Rust programmer. That generally means:
65+
```rust
66+
impl MyType {
67+
fn by_box_to_rc(self: Box<Rc<Self>>) { ... }
68+
}
69+
```
3270

33-
- Introducing new named concepts.
34-
- Explaining the feature largely in terms of examples.
35-
- Explaining how Rust programmers should *think* about the feature, and how it should impact the way they use Rust. It should explain the impact as concretely as possible.
36-
- If applicable, provide sample error messages, deprecation warnings, or migration guidance.
37-
- If applicable, describe the differences between teaching this to existing Rust programmers and new Rust programmers.
38-
- Discuss how this impacts the ability to read, understand, and maintain Rust code. Code is read and modified far more often than written; will the proposed feature make code easier to maintain?
71+
## Object safety
3972

40-
For implementation-oriented RFCs (e.g. for compiler internals), this section should focus on how compiler contributors should think about the change, and give examples of its concrete impact. For policy RFCs, this section should provide an example-driven introduction to the policy, and explain its impact in concrete terms.
73+
The `Receiver` trait is object safe.
4174

4275
# Reference-level explanation
4376
[reference-level-explanation]: #reference-level-explanation

0 commit comments

Comments
 (0)