Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hierarchy of Sized traits #3729

Open
wants to merge 64 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
45d9eac
hierarchy of sized traits
davidtwco Oct 4, 2024
dedc078
updates from EuroRust discussions
davidtwco Oct 14, 2024
2eaaddb
updates post niko-discussion
davidtwco Oct 16, 2024
20e7454
add reasoning about constness
davidtwco Oct 17, 2024
8a8c5a9
add diamond hierarchy
davidtwco Oct 17, 2024
592d192
using const traits
davidtwco Oct 21, 2024
9eecd57
improved diagram
davidtwco Oct 22, 2024
55b8779
address review comments
davidtwco Oct 30, 2024
7849df0
future possibility for externref
davidtwco Nov 12, 2024
f5a5cfc
dynsized -> valuesized
davidtwco Nov 14, 2024
d222516
"statically known at runtime" -> "runtime constant"
davidtwco Nov 14, 2024
337c2e3
elaborate on determining runtime-sized size
davidtwco Nov 14, 2024
aa2a39b
const-stable size_of_val + ed. migration detail
davidtwco Nov 14, 2024
226ca5f
remove const pointee
davidtwco Nov 14, 2024
a0f7bb7
elaborate on runtime-sized const prohibition
davidtwco Nov 14, 2024
2eae11e
add acknowledgements section
davidtwco Nov 14, 2024
dcf2b84
mention PhantomData
davidtwco Nov 14, 2024
487de4d
mention extension options
davidtwco Nov 14, 2024
26f0ace
move to correct filename
davidtwco Nov 15, 2024
a840d8b
correct Copy is a subtrait of Sized
davidtwco Nov 15, 2024
260c980
correct supertrait/subtrait
davidtwco Nov 16, 2024
95a1b7d
remove rust= from code blocks
davidtwco Nov 16, 2024
b670517
correct usage of const trait
davidtwco Nov 16, 2024
b8ea881
mention context for dynamic stack allocation
davidtwco Nov 16, 2024
a703feb
use current const trait syntax
davidtwco Nov 16, 2024
fad04b0
correct incorrect syntax
davidtwco Nov 16, 2024
2fb3aaa
list all alternate bounds
davidtwco Nov 16, 2024
23cb8a2
mention ?Trait being accepted for non-Sized
davidtwco Nov 16, 2024
0c2f6e6
use distinct Pointee trait
davidtwco Nov 16, 2024
397e474
correct bound in size_of_val description
davidtwco Nov 16, 2024
6c1482b
update info about size_of_val and align_of_val
davidtwco Nov 16, 2024
1f85898
correct extern types in structs
davidtwco Nov 16, 2024
5f4b8ff
elaborate on implicit relaxation
davidtwco Nov 18, 2024
ab8e7f6
further clarify ?Sized alternative
davidtwco Nov 19, 2024
b050c2b
reword references to relaxed bounds
davidtwco Nov 19, 2024
432a77a
strengthen drawback of implicit relaxation
davidtwco Nov 19, 2024
98af888
mention rfl want
davidtwco Nov 19, 2024
60eab1a
weaken language around externref
davidtwco Nov 19, 2024
6e124e5
further extend ?sized alternatives
davidtwco Nov 19, 2024
4faeb83
remove implicit relaxation terminology
davidtwco Nov 19, 2024
b4258c7
mention backwards incompatiblity with trait methods
davidtwco Nov 25, 2024
61f8d6d
changed aligned future possibility
davidtwco Nov 25, 2024
9158ebb
elaborate on implicit supertrait
davidtwco Nov 25, 2024
b71401c
elaborate further on implicit supertraits
davidtwco Nov 26, 2024
c9e71bd
add alternative about metasized/mutexes
davidtwco Nov 26, 2024
5573be7
further further elaboration on implicit supertraits
davidtwco Nov 27, 2024
2831cca
fix heading level of alternative
davidtwco Nov 27, 2024
ef2f5cd
elaborate on metasized and unsafecell
davidtwco Nov 29, 2024
145446d
clarify return types
davidtwco Nov 29, 2024
b620534
clarify that non-const sized is not nameable
davidtwco Dec 2, 2024
02d1759
clarify which pointee
davidtwco Dec 2, 2024
8cbaef9
clarify relaxed bounds tables
davidtwco Dec 2, 2024
72743b6
further clarifications around relaxed bounds
davidtwco Dec 2, 2024
9fd3dff
runtime-sized in const is unsound
davidtwco Dec 2, 2024
462d016
clarify wording of unresolved metasized question
davidtwco Dec 2, 2024
57b9a85
replace valuesized with metasized
davidtwco Dec 9, 2024
aa21450
elaborate on backwards incompat with methods
davidtwco Dec 9, 2024
c0ee97d
match indentation in code blocks
davidtwco Dec 9, 2024
7a11fe9
fix list of when traits are implemented
davidtwco Dec 12, 2024
762c6d8
add example of clone supertrait relaxation
davidtwco Dec 12, 2024
52b776f
rationale for delaying size_of bound relaxation
davidtwco Dec 17, 2024
5d602fb
s/alignment/size
davidtwco Jan 8, 2025
d6d73b2
add unresolved question for `std::ptr::Pointee` use
davidtwco Jan 8, 2025
f26784b
clarify that pointee is not semantically necessary
davidtwco Jan 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
updates from EuroRust discussions
  • Loading branch information
davidtwco committed Nov 14, 2024
commit dedc07803a8dea2c3fee46e8e9d249e731ac6742
112 changes: 94 additions & 18 deletions text/0000-sized-hierarchy.md
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
- Start Date: 2024-09-30
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary
[summary]: #summary

@@ -89,6 +90,24 @@ Introducing a hierarchy of `Sized` traits will enable extern types to implement
a trait for unsized types and therefore not meet the bounds of `size_of_val`
and `align_of_val`.

# Terminology
[terminology]: #terminology

In the Rust community, "unsized" and "dynamically sized" are often used
interchangeably to describe any type that does not implement `Sized`. This is
unsurprising as any type which does not implement `Sized` is necessarily
"unsized" and the only types this description captures are those which are
dynamically sized.

In this RFC, a distinction is made between "unsized" and "dynamically sized"
types. Unsized types is used to refer only to those which have no known
size/alignment, such as those described by [the extern types
RFC][rfc_extern_types]. Dynamically-sized types describes those types whose size
cannot be known statically at compilation time and must be computed at runtime.

Within this RFC, no terminology is introduced to describe all types which do not
implement `Sized` in the same sense as "unsized" is colloquially used.

# Guide-level explanation
[guide-level-explanation]: #guide-level-explanation
Most types in Rust have a size known at compilation time, such as `u32` or
@@ -236,6 +255,15 @@ but only as the last field.
As `RuntimeSized`, `DynSized` and `Unsized` are not default bounds, there is no
equivalent to `?Sized` for these traits.

There is a potential performance impact within the trait system to adding
supertraits to `Sized`, as implementation of these supertraits will need to be
proven whenever a `Sized` obligation is being proven (and this happens very
frequently, being a default bound). It may be necessary to implement an
optimisation whereby `Sized`'s supertraits are assumed to be implemented and
checking them is skipped - this should be sound as all of these traits are
implemented by the compiler and therefore this property can be guaranteed by
the compiler implementation.

## Edition changes
[edition-changes]: #edition-changes

@@ -247,8 +275,8 @@ Sized` bounds can be trivially rewritten to `DynSized` bounds by `rustup`.
[auto-traits-and-backwards-compatibility]: #auto-traits-and-backwards-compatibility

A hierarchy of `Sized` traits sidesteps [the backwards compatibility hazards
which typically scupper attempts to add new traits implemented on every type]
[changing_rules_of_rust].
which typically scupper attempts to add new traits implemented on every
type][changing_rules_of_rust].

Adding a new auto trait to the bounds of an existing function would typically
be a breaking change, despite all types implementing the new auto trait, in
@@ -287,36 +315,50 @@ fn std_fn<T: NewAutoTrait>(value: T) { /* .. */ }
equivalent to a `T: DynSized` bound, as described earlier. Therefore there would
be no change as `T: DynSized` implies the changed or relaxed bound.

```rust
fn user_fn<T>(value: T) { std_fn(value) } // T: Sized, so T: RuntimeSized
fn std_fn<T: RuntimeSized>(value: T) { /* .. */ }
```
```rust
fn user_fn<T>(value: T) { std_fn(value) } // T: Sized, so T: RuntimeSized
fn std_fn<T: RuntimeSized>(value: T) { /* .. */ }
```

If an existing function's generic parameter had a `?Sized` bound and this
bound were changed to `RuntimeSized` then this *would* be a breaking change, but
it is not expected that this change would be applied to any existing functions
in the standard library.
If an existing function's generic parameter had a `?Sized` bound and this
bound were changed to `RuntimeSized` then this *would* be a breaking change, but
it is not expected that this change would be applied to any existing functions
in the standard library.

The proposed traits in this RFC are only a non-breaking change because the
new auto traits are being added as subtraits of `Sized`, adding supertraits of
`Sized` would be a breaking change.
The proposed traits in this RFC are only a non-breaking change because the
new auto traits are being added as subtraits of `Sized`, adding supertraits of
`Sized` would be a breaking change.

2. Trait objects passed by callers would not imply the new trait. For example,
adding a new auto trait as a bound to `std_fn` would cause `user_fn` to stop
compiling as its trait object would not automatically implement the new auto
trait:

```rust
fn user_fn(value: Box<dyn ExistingTrait>) { std_fn(value) }
fn std_fn<T: NewAutoTrait>(value: &T) { /* ... */}
//~^ ERROR the trait bound `dyn ExistingTrait: NewAutoTrait` is not satisfied in `Box<dyn ExistingTrait>`
```
```rust
fn user_fn(value: Box<dyn ExistingTrait>) { std_fn(value) }
fn std_fn<T: NewAutoTrait>(value: &T) { /* ... */}
//~^ ERROR the trait bound `dyn ExistingTrait: NewAutoTrait` is not satisfied in `Box<dyn ExistingTrait>`
```

Like the previous case, due to the proposed traits being subtraits of
`Sized`, and every trait object implementing `Sized`, adding a `RuntimeSized`,
`DynSized`, or `Unsized` bound to any existing generic parameter would be
already satisfied.

Additionally, it is not expected that this RFC's additions would result in much
churn within the ecosystem. All bounds in the standard library should be re-evaluated
during the implementation of this RFC, but bounds in third-party crates need not be:

Up-to-`RuntimeSized`-implementing types will primarily be used for localised
performance optimisation, and `Unsized`-only-implementing types will primarily be
used for localised FFI, neither is expected to be so pervasive throughout Rust
software to the extent that all existing `Sized` or `?Sized` bounds would need to
be immediately reconsidered in light of their addition. If a user of a
up-to-`RuntimeSized`-implementing type or a `Unsized`-only-implementing type did
encounter a bound that needed to be relaxed, this could be changed in a patch to
the relevant crate without breaking backwards compatibility as-and-when such bounds
are discovered.

## Changes to the standard library
[changes-to-the-standard-library]: #changes-to-the-standard-library

@@ -390,9 +432,43 @@ There are various points of difference to the [prior art](#prior-art) related to
traits. Custom DSTs are still compatible with this proposal using a `Contiguous`
trait as in [rfcs#2594][rfc_custom_dst_electric_boogaloo].

## Bikeshedding
All of the trait names proposed in the RFC can be bikeshed and changed, they'll
ultimately need to be decided but aren't the important part of the RFC.

## Why have `Unsized`?
It may seem that the `Unsized` trait is unnecessary as this is equivalent to the
absense of any bounds whatsoever, but having an `Unsized` trait is necessary to
enable the meaning of `?Sized` to be re-defined to be equivalent to `DynSized`
and avoid complicated behaviour change over an edition.

Without `Unsized`, if a user wanted to remove all sizedness bounds from a generic
parameter then they would have two options:

1. Introduce new relaxed bounds (i.e. `?DynSized`), which has been found
unacceptable in previous RFCs ([rfcs#2255][issue_more_implicit_bounds]
summarizes these discussions)
2. Maintain `?Sized`'s existing meaning of removing the implicit `Sized` bound
- This could be maintained with or without having the existence of bounds
for `RuntimeSized` and `DynSized` remove the implicit `Sized` bound.

The latter is the only viable option, but this would complicate changing
`size_of_val`'s existing `?Sized` bound.

`?Sized` can be redefined to be equivalent to `DynSized` in all editions
and the syntax can be removed in a future edition only because adding an
`Unsized` bound is equivalent to removing the `Sized` bound and imposing
no constraints on the sizedness of a parameter.

Without `Unsized`, a complicated migration would be necessary to change
all current uses of `?Sized` to `DynSized` (as these are equivalent) and
then future uses of `?Sized` would now accept more types than `?Sized`
previously did (they would now accept the `extern type`s).

In [rfcs#3396][rfc_extern_types_v2], `MetaSized` was introduced and used a
similar mechanism over an edition to redefine `?Sized`.

## Alternatives to this RFC
There are not many alternatives to this RFC to unblock `extern type`s and
scalable vectors: