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 55 commits into
base: master
Choose a base branch
from

Conversation

davidtwco
Copy link
Member

@davidtwco davidtwco commented Nov 15, 2024

All of Rust's types are either sized, which implement the Sized trait and have a statically known size during compilation, or unsized, which do not implement the Sized trait and are assumed to have a size which can be computed at runtime. However, this dichotomy misses two categories of type - types whose size is unknown during compilation but is a runtime constant, and types whose size can never be known. Supporting the former is a prerequisite to stable scalable vector types and supporting the latter is a prerequisite to unblocking extern types. This RFC proposes a hierarchy of Sized traits in order to be able to support these use cases.

This RFC relies on experimental, yet-to-be-RFC'd const traits, so this is blocked on that. I haven't squashed any of the previous revisions but can do so if/when this is approved. Already discussed in the 2024-11-13 t-lang design meeting with feedback incorporated.

See this comment for the most recent summary of changes to this RFC since it was opened.

Rendered

@davidtwco davidtwco added the T-lang Relevant to the language team, which will review and decide on the RFC. label Nov 15, 2024
Co-authored-by: León Orell Valerian Liehr <[email protected]>
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
@tmandry tmandry added the I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. label Nov 15, 2024
@davidtwco
Copy link
Member Author

davidtwco commented Nov 25, 2024

For those following along or catching up, these are the notable the changes to the RFC since this was posted:

  • Clarify proposed behaviour for ?Trait syntax for non-Sized, which is currently accepted
  • Stop re-using std::ptr::Pointee and make Pointee its own new marker trait to avoid backwards incompatibility
  • Clarify backwards compatibility implications of ?Sized syntax and add alternatives to removing the default bound using positive bounds which continue to use ?Sized
  • Add that relaxing existing bounds in trait methods would be backwards incompatible
  • Elaborate on necessity of implicit const ValueSized bound on Self type of traits
  • Add MetaSized alternative to ValueSized which would resolve interactions with mutexes
  • Clarified that bounds on return types can never be relaxed.

And these are all the other smaller changes that don't materially impact what is being proposed:

  • Fixed some minor wording errors where supertrait/subtrait were used backwards
  • Removed HackMD's rust= syntax from codeblocks
  • Fixed referring to the introduction of a const Sized trait, but rather adding a const modifier to the existing Sized trait
  • Added some background/context on dynamic stack allocation
  • Use current experimental const trait syntax
  • Corrected incorrect syntax for traits
  • Listed all alternate bounds (adding ~const ValueSized to a list of bounds that it was missing from)
  • Fixed bound in description of size_of_val changes
  • Corrected description of current size_of_val and align_of_val behaviour
  • Corrected description of extern type usage in structs
  • Mention Rust for Linux's interest in extern type
  • Weaken language in the externref future possibility to make it clear this proposal would not be sufficient on its own to support these
  • Re-write Aligned future possibility so that it is clear Aligned couldn't be added to the proposed hierarchy

I've yet to respond to and/or incorporate the following comments, but will be working on those this week:

At the moment, I prefer the following alternatives to the primary proposal of the RFC, and may re-write to incorporate these as the primary proposal:

@RalfJung
Copy link
Member

RalfJung commented Nov 30, 2024

I'm only arguing that ?Sized is undesirable as:

  • They're more confusing than my proposed alternative

I guess I just disagree with this. It's a subjective statement anyway.

I would appreciate if the RFC could list the syntax as an unresolved question: should there be some clear syntactic marker that the default bound is removed, or are we okay with that being an entirely implicit side-effect of adding another bound? I am not sure if it is necessary to commit to a particular syntax for this already, and seeing this used in practice will help determine how confusing it really is.

As one point for why this is confusing, imagine I have

trait MyTrait: const ValueSized {}

and now I write T: MyTrait. I presume that under your RFC, this is not equivalent to T: MyTrait + const ValueSized, since the latter opts-out of the default bound, but the former does not! That's non-compositional and odd, and IMO the RFC should clearly acknowledge this and make sure we get back to this question before stabilization (by listing it as an unresolved question).

Adding MetaSized (either replacing ValueSized or in addition to it), as per the "What about MetaSized instead of or in addition to ValueSized?" section.

👍 , given that all the types we currently have determine their size based on the metadata, not the value, this seems prudent. The name of size_of_val can be considered unfortunate in that context, but the function does take a value, so it makes some sense.

Using ?Trait syntax instead of positive bounds as per "Adding ?ValueSized"

So the idea is that ?Sized opts-out of the default bound, but then adds another default bound of ValueSized? Hm... this variant has less syntactic noise than mine, but it is not the behavior I would have naively expected. But I guess it can be taught coherently: a ?Bound relaxes default bounds just enough to make it so that Bound may or may not hold, but all supertraits of Bound (if any) are still present.

?const ValueSized is a bit odd though, it has to be interpreted as ?(const ValueSized) to make sense with this model, even though it looks like like (?const) ValueSized. (?const) ValueSized would be like adding a ValueSized bound and being in a world where that trait is by default const, and then we opt-out of that default constness. If we go with this syntax, we better never have "traits that are const by default", i.e. we better make it so that (?const) ValueSized is never a valid interpretation of this bound.

text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
text/3729-sized-hierarchy.md Outdated Show resolved Hide resolved
@davidtwco
Copy link
Member Author

I would appreciate if the RFC could list the syntax as an unresolved question: should there be some clear syntactic marker that the default bound is removed, or are we okay with that being an entirely implicit side-effect of adding another bound? I am not sure if it is necessary to commit to a particular syntax for this already, and seeing this used in practice will help determine how confusing it really is.

I've added this as an unresolved question.

As one point for why this is confusing, imagine I have

trait MyTrait: const ValueSized {}

and now I write T: MyTrait. I presume that under your RFC, this is not equivalent to T: MyTrait + const ValueSized, since the latter opts-out of the default bound, but the former does not! That's non-compositional and odd, and IMO the RFC should clearly acknowledge this and make sure we get back to this question before stabilization (by listing it as an unresolved question).

That makes sense. You're right that T: MyTrait would not imply removal of the default bound, it would be T: const Sized + MyTrait unless you wrote T: MyTrait + const ValueSized (or T: MyTrait + ?Sized if we go that way). In Niko's blog post, he suggested it could be that T: MyTrait implies removal of the default bound. I mention that what I have proposed is compatible with that but don't propose it at the moment.

👍 , given that all the types we currently have determine their size based on the metadata, not the value, this seems prudent. The name of size_of_val can be considered unfortunate in that context, but the function does take a value, so it makes some sense.

I've added this as an unresolved question too.

?const ValueSized is a bit odd though, it has to be interpreted as ?(const ValueSized) to make sense with this model, even though it looks like like (?const) ValueSized. (?const) ValueSized would be like adding a ValueSized bound and being in a world where that trait is by default const, and then we opt-out of that default constness. If we go with this syntax, we better never have "traits that are const by default", i.e. we better make it so that (?const) ValueSized is never a valid interpretation of this bound.

I've added explicit parentheses to make this clearer for now until a const Traits RFC clarifies this.

| `Sized` | `T: Sized` | `T: ?(const Sized) + Sized` |
| `const ValueSized` | `T: const ValueSized` | `T: ?(const Sized) + const ValueSized` |
| `ValueSized` | `T: ValueSized` | `T: ?(const Sized) + ValueSized` |
| `Pointee` | `T: Pointee` | `T: ?(const Sized)` |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `Pointee` | `T: Pointee` | `T: ?(const Sized)` |
| `Pointee` | `T: Pointee` | `T: ?(const Sized) + Pointee` |

in the future some types may not implement Pointee such as wasm externref types

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true but I've written all of the guide-level and reference-level explanation sections assuming that the future possibilities are not included.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.