Hierarchy of Sized traits
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.
In contrast to [...], none of the traits proposed in this RFC are default bounds and therefore do not need to support being relaxed bounds, which avoids additional language complexity and backwards compatibility hazards related to relaxed bounds and associated types
This feels dishonest to me. The proposed ValueSized trait is effectively a default bound (by virtue of being a supertrait of Sized), and it can be relaxed implicitly by adding a Pointee bound.
What's the reason for deprecating the ?Sized syntax rather than adding ?ValueSized? There's a list of problems with relaxed trait bounds in this issue, but it's easy to see that those problems aren't addressed in this RFC:
Expand to see the reasoning
-
?Sizeditself being a "negative feature" confuses users, adding?Moveand?DynSizedwill only make the situation worseI would argue that this proposal, where adding a
PointeeorValueSizedbound implicitly relaxes the defaultconst Sizedbound, will confuse people even more.?Sizedis explicit and it can be intuitively understood as "maybe sized". A trait bound that automatically relaxes another trait bound is neither intuitive, nor explicit. -
introducing new relaxed bound means downstream packages will need to reevaluate every api to see if adding
: ?Traitmakes senseThe same is true under this proposal. Except users need to reevaluate if adding
: Sized,: const ValueSized,: ValueSized, or: Pointeemakes sense.However, the RFC states, without proof, that this is not the case:
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.
-
the necessity of
MoveandDynSizedis orthogonal to whether they need to be default.I don't even understand this argument. It has been established that
DynSized(orValueSized) is necessary to make extern types sound, and it needs to be a default bound for backward compatibility ofsize_of_val(). -
the backward-compatibility may be a lie 🍰 — Relaxing the bounds in associated type, in particular
FnOnce::Output, means the user of the trait will get less promises, which is a breaking change [...]Essentially, the bounds on an associated type cannot be added (which breaks implementers) or removed (which breaks users).
This is true for
?Sizedbounds, and will also be true forValueSizedandPointeebounds under this RFC.
The only benefit of the proposal I can see is that it works well with ~const Sized and ~const ValueSized bounds. But I'm not sure if this justifies deprecating a well-known language feature, when the new syntax has such a big drawback:
This RFC's proposal that adding a bound of
const Sized,const ValueSized,ValueSizedorPointeewould remove the defaultSizedbound is somewhat unintuitive.
"somewhat" being a massive understatement.
FWIW I agree with @Aloso . I tried to figure out in https://github.com/rust-lang/rfcs/issues/2255 what the reason is for preferring "magic traits where adding one bound removes another bound" over ?Trait, but so far I didn't get it.
In contrast to [...], none of the traits proposed in this RFC are default bounds and therefore do not need to support being relaxed bounds, which avoids additional language complexity and backwards compatibility hazards related to relaxed bounds and associated types
This feels dishonest to me. The proposed
ValueSizedtrait is effectively a default bound (by virtue of being a supertrait ofSized), and it can be relaxed implicitly by adding aPointeebound.
There's nothing dishonest about this. ValueSized may effectively be a default bound, but it isn't one, and as such does not need its own relaxed bound syntax and avoids the backwards compatibility hazards that entails. This is a point of difference between this RFC and much of the referenced prior art, hence this being explicitly stated.
I would argue that this proposal, where adding a
PointeeorValueSizedbound implicitly relaxes the defaultconst Sizedbound, will confuse people even more.?Sizedis explicit and it can be intuitively understood as "maybe sized". A trait bound that automatically relaxes another trait bound is neither intuitive, nor explicit.
We can agree to disagree. ?Sized is notoriously confusing for new users, and this been at least part of the motivation for the language team's historical reluctance to add new ?Trait syntax.
?Sized is definitely familiar to experienced Rust users, that's a downside of what this RFC proposes, certainly, but I don't think that it is otherwise any more or less intuitive than ?Sized syntax: it's a special-case that a user needs to learn when they want to relax the only default bound that the language has, it's just a different way to do that. It is somewhat less explicit, but it's not entirely implicit, a default Sized bound isn't just disappearing without anything written in the source to indicate that is happening, the less-strict bound will be present.
introducing new relaxed bound means downstream packages will need to reevaluate every api to see if adding
: ?Traitmakes senseThe same is true under this proposal. Except users need to reevaluate if adding
: Sized,: const ValueSized,: ValueSized, or: Pointeemakes sense.However, the RFC states, without proof, that this is not the case:
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.
In the first comment you quote from, the discussion is around ?Trait syntax in general, in which case I would agree with it. For something like ?Leak or ?Move or any number of other proposals for new auto traits, you may need to re-evaluate APIs more readily.
However, the sentence you're quoting from this RFC is made within a larger context where it does makes sense: the specific claim that this RFC makes is that bounds do not need to be re-evaluated during implementation of the RFC.
If a bound was not re-evaluated and this feature was stabilised, and re-evaluation would have found that the bound should have been relaxed, it still could be - that's why a bound in third-party crate would not need to be re-evaluated. Furthermore, the RFC also argues that due to the nature of the specific use-cases that this RFC traits aims to support, if the vast majority of the ecosystem never re-evaluate their bounds, that wouldn't be a major issue, because use of types with these exotic sizes are likely to be localised.
the backward-compatibility may be a lie 🍰 — Relaxing the bounds in associated type, in particular
FnOnce::Output, means the user of the trait will get less promises, which is a breaking change [...]Essentially, the bounds on an associated type cannot be added (which breaks implementers) or removed (which breaks users).
This is true for
?Sizedbounds, and will also be true forValueSizedandPointeebounds under this RFC.
That's true, is noted in the RFC, and is why the RFC doesn't propose changing the bounds of any associated types to use these new traits.
It's also worth noting that the alternative approach to ?Sized isn't load-bearing to this proposal, it's still possible to introduce a hierarchy of Sized traits and keep ?Sized. I've just added a section to the alternatives elaborating on this possibility so that the language team can consider that when they discuss this RFC. I don't think that's the right approach, primarily as it doesn't scale well to the hierarchies of traits and constness that this RFC proposes, which is why it's an alternative and not the primary proposal of the RFC.
There's nothing dishonest about this. ValueSized may effectively be a default bound, but it isn't one, and as such does not need its own relaxed bound syntax and avoids the backwards compatibility hazards that entails.
The backwards compatibility issue is an actual semantic problem. Choosing different syntax cannot possibly help here. So I still don't understand why you claim that avoiding ? somehow avoids backwards compatibility issues.
There is indeed a backwards compatibility issue with ?Move, but it is not caused by ?. It is caused by having the concept of non-movable types in any way, shape, or form. Adding ?Move itself is not backwards-incompatible. Only adding ?Move to any already existing associated type is backwards-incompatible. Similarly, under your proposal, changing the bound of any associated type in the standard library to Pointee would be a breaking change. The only difference to Move is that we'd almost certainly want to add ?Move to a ton of existing associated types, but we hopefully won't want to weaken any of the existing associated types to Pointee. The syntax we use for writing these bounds doesn't matter.
If we used ? syntax to mark the opt-out, things would work exactly the same: any existing associated type keeps its existing const Sized bound, except for the ?Sized ones which get a ?Sized + const ValueSized bound (where ?Sized entirely removes all implicit sized-related bounds, and then const ValueSized adds back the bound we are looking for; other options are possible of course). This is exactly as backwards-compatible as your proposal.
It would be good to do a survey of ?Sized associated types in the standard library and figure out if any of them should be weaker than const ValueSized... but due to the inherent backwards compatibility issues, it's unlikely we'll be able to do that for any of them. The only one that comes to my mind is Deref::Target.
To be clear, my main issue here is that the RFC misrepresents the trade-off between ? syntax and the proposed syntax. As far as I can tell, this trade-off is entirely syntactical, the two options are fully equivalent in terms of backwards compatibility or any other semantic concern. If the lang team wants to pick the "magic trait bound that removes an implicit bound" over "magic ? bound", then sure whatever (I have my preference but generally try to stay out of purely syntactic discussions). But we shouldn't be under the impression that this would make any difference for the transition plan to the new hierarchy.
Specifically, there's this part here:
which avoids additional language complexity and backwards compatibility hazards related to relaxed bounds and associated types
which doesn't explain how "magic trait bound that removes an implicit bound" has less language complexity than "magic ? bound that removes an implicit bound" -- I think both have the exact same underlying complexity in terms of abstractly describing their semantics. If anything, the ?Sized version has less complexity since one can easily tell whether a bound removes implicit bounds or not. And it claims relaxed bounds have backwards compatibility hazards which are avoided by this RFC's hierarchy, which is just not correct.
And this:
Introduce a ?ValueSized relaxed bound (a user could write Sized, ValueSized or ?ValueSized) which has been found unacceptable in previous RFCs (https://github.com/rust-lang/rfcs/issues/2255 summarizes these discussions).
I tried to find a summary in #2255 that correctly reflects the situation as it applies to this RFC, and couldn't find it.
And then this comes up in some of the items in the (extremely impressive!) detailed comparison list. For instance, these are not valid arguments I think. for the reasons mentioned above:
Downstream crates need to re-evaluate every API to determine if adding ?Trait makes sense, for each ?Trait added.
?Trait isn't actually backwards compatible like everyone thought due to interactions with associated types.
This all needs a pass to avoid misrepresenting relaxed bounds. (I'm happy to help with that, once we agree that this should be done.)
To be clear, my main issue here is that the RFC misrepresents the trade-off between
?syntax and the proposed syntax. As far as I can tell, this trade-off is entirely syntactical, the two options are fully equivalent in terms of backwards compatibility or any other semantic concern.
I'm not arguing that the syntax that this proposes makes a difference w/r/t backwards compatibility, it doesn't. In the new section that I added earlier today in response to your concerns, I describe how this proposal could still work with ?Sized.
Specifically, there's this part here:
which avoids additional language complexity and backwards compatibility hazards related to relaxed bounds and associated types
which doesn't explain how "magic trait bound that removes an implicit bound" has less language complexity than "magic
?bound that removes an implicit bound" -- I think both have the exact same underlying complexity in terms of abstractly describing their semantics.
In the paragraph that you've quoted, all I'm arguing is that this RFC, unlike much of the prior art, doesn't introduce a new relaxed bound, like ?ValueSized, and as such avoids backwards compatibility hazards related to relaxed bounds. It does not argue that moving away from ?Sized is in any way necessary for avoiding backwards incompatibility.
There's nothing dishonest about this. ValueSized may effectively be a default bound, but it isn't one, and as such does not need its own relaxed bound syntax and avoids the backwards compatibility hazards that entails.
The backwards compatibility issue is an actual semantic problem. Choosing different syntax cannot possibly help here. So I still don't understand why you claim that avoiding ? somehow avoids backwards compatibility issues.
Likewise here, I agree, the backwards compatibility is a semantic problem, the syntax doesn't make a difference. I'm not claiming that avoiding ? will avoid backwards compatibility issues (other than that adding entirely new relaxed bounds is undesirable). I was responding to the claim that ValueSized is effectively a default bound, by making it clear that it is not a default bound, and therefore does not require a new relaxed bound.
If we used ? syntax to mark the opt-out, things would work exactly the same: any existing associated type keeps its existing const Sized bound, except for the ?Sized ones which get a ?Sized + const ValueSized bound (where ?Sized entirely removes all implicit sized-related bounds, and then const ValueSized adds back the bound we are looking for; other options are possible of course). This is exactly as backwards-compatible as your proposal.
I agree! I've written a section of the RFC that describes this possibility, I don't prefer it, but I do agree.
I think the misunderstanding here may be that the situation around relaxed bounds and backwards incompatibility may be more nuanced than I initially remembered (it's been a month or two since I wrote the prior art section and decided against introducing new relaxed bounds) - I've said in the RFC that introducing them has backwards compatibility hazards (comments like this one being fresh in mind writing that), and they do, but only in some circumstances.
That said, and correct me if I'm wrong, but neither of us are arguing for introducing new relaxed bounds, like ?ValueSized, so it's a bit of a moot point as we both agree that continuing to use ?Sized is backwards compatible and an alternative to what I propose.
I'm only arguing that ?Sized is undesirable as:
- They're more confusing than my proposed alternative
- They don't scale very well to constness
- They don't scale very well to hierarchies
These are subjective, and I expect that you disagree. I added a section earlier today on keeping ?Sized as an alternative, and I'd be interested in knowing if there's anything in that you disagree with.
?Sizedis notoriously confusing for new users, and this has motivated the language team's historical reluctance to adding new?Traitsyntax.
As a minor clarification, we support ?Trait syntax rather pervasively, e.g.:
trait Tr {}
fn f<T: ?Tr>() {} //~ OK
What we've been reluctant to do is to add new traits liked Sized that are implicitly added to bounds.
Has our reluctance been primarily motivated by confusion for new users? I don't know. There are other compelling reasons that would have made it difficult to add new implicitly-added bounds in the kind of cases we've previously considered, such as the well known backward compatibility problems with respect to associated types on existing traits.
One reason, IIRC, is that it's backwards from how you normally think about traits. We'd generally rather that you write the easy thing, it's minimally-constrained, and if you use something in the body that needs another trait, we'll give you an error message saying that you should add the bound.
Anywhere you'd have to think "did I opt out of those 4 other things that I need to remember to think about?" is a much worse experience. That's why auto traits in libraries might never be stable, for example.
@davidtwco
We can agree to disagree.
?Sizedis notoriously confusing for new users, and this been at least part of the motivation for the language team's historical reluctance to add new?Traitsyntax.
If a new user sees T: ?Sized for the first time, they may be confused for a moment, then google it and find the documentation, which explains it.
If a new user sees T: ValueSized for the first time, they will not be confused because it looks familiar. They will not google it, and stay oblivious to the fact that this bound removes the default const Sized bound.
If a new user runs into an error due to a missing ?Sized bound, they see something like
help: consider relaxing the implicit `Sized` restriction
|
2 | type Item: ?Sized;
| ++++++++
I understand that this is confusing at first, but is this better?
help: consider adding a `ValueSized` bound, which relaxes the implicit `Sized` restriction
|
2 | type Item: ValueSized;
| ++++++++++++
It requires you to learn about two traits instead of one, and you still find out that Sized is a default bound and needs to be relaxed. The ?Trait syntax is not a problem, people don't struggle to learn Rust because of its syntax. Learning syntax is easy.
I'm only arguing that ?Sized is undesirable as:
- They're more confusing than my proposed alternative
- They don't scale very well to constness
- They don't scale very well to hierarchies
I agree with the second point. I don't agree with the 3rd point: When I see ?Trait and Trait has a sub-trait, it is natural to assume that the sub-trait is relaxed as well. So ?const Sized means Sized, ?Sized means ValueSized, and ?ValueSized means no bounds (since there is no need for the Pointee trait). But a const ValueSized bound would have to be written as ?Sized + const ValueSized.
P.S. I just realized that ?Sized should be equivalent to const ValueSized according to this RFC, which is not as intuitive. Unless ?Trait only relaxes the trait, ?const Trait relaxes only the constness, and ?const ?Trait relaxes both. But this is pretty ugly.
If a new user sees
T: ?Sizedfor the first time, they may be confused for a moment, then google it and find the documentation, which explains it.If a new user sees
T: ValueSizedfor the first time, they will not be confused because it looks familiar. They will not google it, and stay oblivious to the fact that this bound removes the defaultconst Sizedbound.
This is conjecture, we have no reason to believe that users will only research unfamiliar syntax like ?Sized, but not unfamiliar traits like ValueSized.
Even if we suppose that your assertion holds and a user sees a parameter with a ValueSized bound and doesn't know what it is and just continues on anyway, they're likely to be able to pass whatever types they'd like to that parameter and not need to think about it. It would only be if they were writing a function, had a ValueSized-bounded parameter and tried to pass it to something like size_of that they'd run into a compilation error. That sounds like an appropriate time for a user to be introduced to that trait and need to understand it.
If a new user runs into an error due to a missing
?Sizedbound, they see something likehelp: consider relaxing the implicit `Sized` restriction | 2 | type Item: ?Sized; | ++++++++I understand that this is confusing at first, but is this better?
help: consider adding a `ValueSized` bound, which relaxes the implicit `Sized` restriction | 2 | type Item: ValueSized; | ++++++++++++
These aren't significantly different. I don't believe users would find the former of these approachable and intuitive any more so than the latter.
It requires you to learn about two traits instead of one, and you still find out that
Sizedis a default bound and needs to be relaxed. The?Traitsyntax is not a problem, people don't struggle to learn Rust because of its syntax. Learning syntax is easy.
I agree that in learning how to relax a default Sized bound users would be introduced to new traits like ValueSized. If we went ahead with this RFC using the alternative that kept the ?Sized syntax, a user is unlikely to want a type unconstrained by all of our sizedness traits due to the limitations these have, so they'll need to add additional bounds using these new traits after using ?Sized.
I don't think it will be especially common, but a user that needs to relax Sized will be introduced to these traits regardless of whether we use ?Sized or what this RFC proposes. If users are going to be introduced to these traits anyway, then if they use ?Sized to opt-out of the default bound or what this RFC proposes is just a matter of syntax, and as you've said, syntax is easy.
Don't get me wrong, adding these traits is adding complexity to the language, but I'd argue that it is essential complexity that reflects the complexity of platforms that Rust targets, rather than incidental complexity.
There is a point that I don't see discussed here: you discuss what will be the learning effect for new users, but we also need to consider experienced user. Thus will understand both more easily, but it'll be much easier for them to learn and remember the existing ?Trait syntax, since they already know and use it.
And a related point: introducing a different way to name what is essentially the same thing introduces inconsistency to the language.
There is a point that I don't see discussed here: you discuss what will be the learning effect for new users, but we also need to consider experienced user. Thus will understand both more easily, but it'll be much easier for them to learn and remember the existing
?Traitsyntax, since they already know and use it.
Yeah, that's definitely a downside of this proposal. I think it's worth it on balance, but it's definitely a downside.
And a related point: introducing a different way to name what is essentially the same thing introduces inconsistency to the language.
I think this should be okay as the proposal removes the previous approach over an edition. It won't be entirely gone, it can't be, but it's as good as we can get it.
One other concern is the ability of reviewers to check for backwards-compatibility.
When reviewing a patch which removes a trait bound, I'd generally assume that doing so is relaxing the requirements on the type being bound-- a backwards-compatible change. However, this would be a rare example where removing the bound would be a breaking change, and adding the bound would be the backwards-compatible change. This is unintuitive to me.
Personally, I prefer the T: ?Trait syntax, which I read as "T may not be an instance of Trait." Relevant to this proposal, I'd also assume that T: ?SuperTrait means T: ?Trait, just as T: SubTrait means T: Trait.
Personally, I prefer the T: ?Trait syntax, which I read as "T may not be an instance of Trait." Relevant to this proposal, I'd also assume that T: ?SuperTrait means T: ?Trait, just as T: SubTrait means T: Trait.
I discussed this with @traviscross too and added another alternative based on this, it actually ends up really quite clean and I think is a compelling alternative to the positive bounds proposal that the RFC has.
If a new user sees
T: ValueSizedfor the first time, they will not be confused because it looks familiar. They will not google it, and stay oblivious to the fact that this bound removes the default constSizedbound.
… the proposal removes the previous approach over an edition.
I agree with the previous comments that it would be undesirable to hide the strangeness of the weakening bound behind a lack of syntax, compared to the status quo. However, I have a suggestion for a third option, if there is going to be an edition change regardless: add a new syntax which is neither a normal bound nor a removal like ?, but a “baseline” bound that nails down where we start.
Let's say the syntax is @Trait (symbol subject to bikeshedding, but we can think of it as “begin @ this point”; it could also perhaps be a contextual keyword). What it would mean is: if no baseline bound is present, the baseline bound is implicitly chosen by the edition — in all current editions, it would be Sized. In future editions, it might be something weaker or stronger. Thus,
<T>is “use implicit default bounds from the current edition”.<T: Sized>is “use the union of the implicit baseline andSized”, thus usually useless as today, but ifValueSizedbecomes the default over an edition, it strengthens the bound toSized.<T: ValueSized>is “use the union of the implicit baseline andValueSized”, so it is useless unless an even weaker bound is made default in a future edition.<T: @Sized>is “the bound isSized, regardless of the current edition” — it matches the 2015-2024 behavior of<T>.<T: @ValueSized>is “the bound isValueSized, regardless of the current edition”.<T: @SomeOtherTrait>is an error by default; the@bound syntax can only be used if:- The trait is one of the traits which have ever been an implicit bound (i.e.
Sizedtoday, perhapsValueSizedin the future). - (Optional, if we want to allow user-defined traits to participate)
SomeOtherTraithas an@bound as a supertrait.
- The trait is one of the traits which have ever been an implicit bound (i.e.
<T: ?Sized>has the 2015-2024 meaning forevermore; edition migration should replace it with@ValueSized.<T: ?SomeOtherTrait>does nothing and issues a warning, as today, even ifSomeOtherTrait=ValueSized,Pointee, etc — the idea is to migrate away from the?syntax, not to expand it.
Every type variable always has either an @ explicit baseline bound, or an edition-dependent implicit baseline bound.
The advantages of this schema are:
-
The syntax tells you that something is going on, and the documentation of the trait can tell you what exactly that is.
-
It doesn’t involve any subtraction of bounds.
-
All code that uses an
@bound is now edition-change-proof; it has picked a named baseline and has opted out of all implicit bounds. This simplifies language evolution questions to the separate choices,- “is there room to split off a new weaker trait to serve this need?”
- “what should the implicit baseline bound for the next edition be?”
and “which of these things can you
?and what does that mean and is it clear?” doesn’t need to be asked. Because the baseline is named, there’s room to add another baseline without saying “this one is the correct one; we definitely got it right this time”. -
If
@is allowed with user-defined traits (that opt in by having their own@supertrait bound), then<T: @Foo>is a concise way to express “this is bounded byFoo,Foo’s supertraits, and nothing else”; thus, it simplifies use-cases where one must today write<T: ?Sized + Foo>in every generic parameter.
Caveat: I haven’t thought about how this interacts with const traits. Also, this is certainly adding complexity to the language; it just might be worth it to unblock extern types and thin DSTs while adding room for even more refinements to the language’s default assumptions about types.
[Update: This idea has been crossposted to https://internals.rust-lang.org/t/baseline-bounds-an-extensible-replacement-for-sized/21892 for visibility.]
For those following along or catching up, these are the notable the changes to the RFC since this was posted:
- Clarify proposed behaviour for
?Traitsyntax for non-Sized, which is currently accepted- 23cb8a227e96452dc63eb78045f58bc259c66153
- Stop re-using
std::ptr::Pointeeand makePointeeits own new marker trait to avoid backwards incompatibility- 0c2f6e6016919faa39792c97a6dca6c435213939, 2831cca24c4db43b8197357bea5ccc4882f410a4
- Clarify backwards compatibility implications of
?Sizedsyntax and add alternatives to removing the default bound using positive bounds which continue to use?Sized- These are particularly valuable additions to the RFC as some of these alternatives are quite viable and have significant advantages
- 5f4b8ff938f94a7f4ae7a76d5a84bc35a219b772, ab8e7f6476aa594c31bdfdb4a7ee56b609f6c153, b050c2b48ebe6faeca0e612f4972afe8466151f0, 432a77aa18941bc3707b7eb20eb0413f0ae18ad1, 6e124e54a41680b580406eea04c887403010fa3c, 4faeb83062dd3e4b26a56338f811cd27f2e2d6cc
- Add that relaxing existing bounds in trait methods would be backwards incompatible
- b4258c7cd29a55dd54dac8bcccc1840e36dfeb9b
- Elaborate on necessity of implicit
const ValueSizedbound onSelftype of traits- 9158ebb0aa3865d6475b3df741632693d3f1d574, b71401c383b33559884b1940ef669276bb8ff29c, 5573be779fb281f04bacc1d9df38e5b670c1d25d
- Add
MetaSizedalternative toValueSizedwhich would resolve interactions with mutexes- c9e71bd21099ea8e0d84cfdc60baabff6eec740b, ef2f5cd86b9c750c5eadf691f1881ab40e2fe00a
- Clarified that bounds on return types can never be relaxed.
- 145446d995e091f034fba1c2f618aa4be3ac927b
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
- a840d8b1563645d4e233c8ec5df5c2288ac3bfb0, 260c980f07f2eed12572d5ba3c25cfbb37e6698d
- Removed HackMD's
rust=syntax from codeblocks- 95a1b7ddadf2649288bcc71aecba4c776261add8
- Fixed referring to the introduction of a
const Sizedtrait, but rather adding a const modifier to the existingSizedtrait- b670517d1eb1d5bd42076a91e8aadccf69352435
- Added some background/context on dynamic stack allocation
- b8ea88152b9fc71ebba58330b17cceda570b57f3
- Use current experimental const trait syntax
- a703feb0a2b492a0416a2d9bdd86d6d95bdcffbc
- Corrected incorrect syntax for traits
- fad04b0a6ab386256cfe06667fb8941196e7cfd4
- Listed all alternate bounds (adding
~const ValueSizedto a list of bounds that it was missing from)- 2fb3aaa63ab75bb37b707a4bf8a9003b34e47742
- Fixed bound in description of
size_of_valchanges- 397e474a2cf81ed7d67e28d17797f8138c26c9f8
- Corrected description of current
size_of_valandalign_of_valbehaviour- 6c1482bc9a4af453360da767310b5b5e2b52bf72
- Corrected description of extern type usage in structs
- 1f85898896a85602d146049726f63f70ee303ffd
- Mention Rust for Linux's interest in extern type
- 98af888300a66c0e25373c23077b9af139b06fc5
- Weaken language in the
externreffuture possibility to make it clear this proposal would not be sufficient on its own to support these- 60eab1ac8b46479d61e791384f9130ef9ff87100
- Re-write
Alignedfuture possibility so that it is clearAlignedcouldn't be added to the proposed hierarchy- 61f8d6dac96406a3f73f4adf11adce64ea3ec39c
I've yet to respond to and/or incorporate the following comments, but will be working on those this week:
- https://github.com/rust-lang/rfcs/pull/3729#discussion_r1856857556 from @Skepfyr and @traviscross
- Can associated type bounds could be relaxed?
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:
- Adding
MetaSized(either replacingValueSizedor in addition to it), as per the "What about MetaSized instead of or in addition to ValueSized?" section. - Using
?Traitsyntax instead of positive bounds as per "Adding?ValueSized"
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.
:+1: , 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.
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 toT: 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_valcan 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 ValueSizedis 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) ValueSizedwould be like adding aValueSizedbound 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) ValueSizedis 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.
Another summary comment!
Here are the previous update summaries copied below so you don't need to uncollapse GitHub comments to find it:
2024-11-25
Summary comment: https://github.com/rust-lang/rfcs/pull/3729#issuecomment-2498703253
For those following along or catching up, these are the notable the changes to the RFC since this was posted:
- Clarify proposed behaviour for
?Traitsyntax for non-Sized, which is currently accepted- 23cb8a227e96452dc63eb78045f58bc259c66153
- Stop re-using
std::ptr::Pointeeand makePointeeits own new marker trait to avoid backwards incompatibility- 0c2f6e6016919faa39792c97a6dca6c435213939, 2831cca24c4db43b8197357bea5ccc4882f410a4
- Clarify backwards compatibility implications of
?Sizedsyntax and add alternatives to removing the default bound using positive bounds which continue to use?Sized- These are particularly valuable additions to the RFC as some of these alternatives are quite viable and have significant advantages
- 5f4b8ff938f94a7f4ae7a76d5a84bc35a219b772, ab8e7f6476aa594c31bdfdb4a7ee56b609f6c153, b050c2b48ebe6faeca0e612f4972afe8466151f0, 432a77aa18941bc3707b7eb20eb0413f0ae18ad1, 6e124e54a41680b580406eea04c887403010fa3c, 4faeb83062dd3e4b26a56338f811cd27f2e2d6cc
- Add that relaxing existing bounds in trait methods would be backwards incompatible
- b4258c7cd29a55dd54dac8bcccc1840e36dfeb9b
- Elaborate on necessity of implicit
const ValueSizedbound onSelftype of traits- 9158ebb0aa3865d6475b3df741632693d3f1d574, b71401c383b33559884b1940ef669276bb8ff29c, 5573be779fb281f04bacc1d9df38e5b670c1d25d
- Add
MetaSizedalternative toValueSizedwhich would resolve interactions with mutexes- c9e71bd21099ea8e0d84cfdc60baabff6eec740b, ef2f5cd86b9c750c5eadf691f1881ab40e2fe00a
- Clarified that bounds on return types can never be relaxed.
- 145446d995e091f034fba1c2f618aa4be3ac927b
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
- a840d8b1563645d4e233c8ec5df5c2288ac3bfb0, 260c980f07f2eed12572d5ba3c25cfbb37e6698d
- Removed HackMD's
rust=syntax from codeblocks- 95a1b7ddadf2649288bcc71aecba4c776261add8
- Fixed referring to the introduction of a
const Sizedtrait, but rather adding a const modifier to the existingSizedtrait- b670517d1eb1d5bd42076a91e8aadccf69352435
- Added some background/context on dynamic stack allocation
- b8ea88152b9fc71ebba58330b17cceda570b57f3
- Use current experimental const trait syntax
- a703feb0a2b492a0416a2d9bdd86d6d95bdcffbc
- Corrected incorrect syntax for traits
- fad04b0a6ab386256cfe06667fb8941196e7cfd4
- Listed all alternate bounds (adding
~const ValueSizedto a list of bounds that it was missing from)- 2fb3aaa63ab75bb37b707a4bf8a9003b34e47742
- Fixed bound in description of
size_of_valchanges- 397e474a2cf81ed7d67e28d17797f8138c26c9f8
- Corrected description of current
size_of_valandalign_of_valbehaviour- 6c1482bc9a4af453360da767310b5b5e2b52bf72
- Corrected description of extern type usage in structs
- 1f85898896a85602d146049726f63f70ee303ffd
- Mention Rust for Linux's interest in extern type
- 98af888300a66c0e25373c23077b9af139b06fc5
- Weaken language in the
externreffuture possibility to make it clear this proposal would not be sufficient on its own to support these- 60eab1ac8b46479d61e791384f9130ef9ff87100
- Re-write
Alignedfuture possibility so that it is clearAlignedcouldn't be added to the proposed hierarchy- 61f8d6dac96406a3f73f4adf11adce64ea3ec39c
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:
- Adding
MetaSized(either replacingValueSizedor in addition to it), as per the "What about MetaSized instead of or in addition to ValueSized?" section. - Using
?Traitsyntax instead of positive bounds as per "Adding?ValueSized"
These are links to the compare with previous versions of the document (switch to the "Files changed" tab and then the rich diff):
- Comparison with the pre-RFC version of this discussed at the language team's design meeting
- Comparison since the previous summary comment
These are the major changes since the last summary:
- Change from
ValueSizedtoMetaSized- 72743b6f72817dd7d8659e67dd4da8b828f6d7aa, 57b9a857880e6d314425cc191e90c09b2e8d6997
- Add unresolved question about whether re-using
std::ptr::Pointeeis important.- d6d73b2ee594654e1c8ec05e37cec1ea4463bc60
These are the minor changes since the last summary:
- Clarify that bounds on parameters used as return types can never be relaxed (return types still need to implement
Sized)- 145446d995e091f034fba1c2f618aa4be3ac927b
- Clarify that non-const
Sizedis not nameable in the current edition due to the backwards compatibility migration, only in the next edition- b620534afeca9d9d469924227a43a3ad09bc0c4c
- Clarify which
Pointee(marker traitPointeeorstd::ptr::Pointee) is referenced in the Custom DSTs future possibility- 02d175949589b5a729eefd52f9cafba03b9fd38e
- Improve clarity of the table describing alternative syntax proposals for relaxing bounds
- 8cbaef99e3b49b5d81883382c01d2d8fab063f56
- Strengthen wording describing use of runtime-sized types in a const context as unsound
- 9fd3dffd95117fa622a6b9f23439bdf896d28611
- Expand on motivation for
MetaSized- 462d016a8f8bc00bf0ce6c10e8f52bcf0903cf87
- Specify that methods of the new traits would be backwards-incompatible too, not just associated types
- aa2145002948a1201201cf7026df2b52841f12e1
- Use the same indentation in code blocks throughout
- c0ee97dadf58a7eec3d2eb10df098b0af855b8d3
- Fix typo in list of when each trait gets implemented
- 7a11fe901b0d977e26ee7749b230f05c01ba53bd
- Add a concrete example of code that would break if a supertrait of
Clonewere relaxed- 762c6d87d0a844ac8f03ebd54c49a26de42d827e
- Added note about potential reasons why delaying relaxation of
size_of's bound might be desirable- 52b776f550853571e93b2014f3ada67e82c89589
- Fixed typo, replacing "alignment" with "size"
- 5d602fb4d2d5ea06201f60fe5160c6b86e70be16
- Rewrote "Why have a
Pointeetrait?" section to clarify that the trait is only necessary due to the proposed removal of?Sizedsyntax- f26784b30e288dfebd1f8178bddb8c4b1ee418c1
- Updated reference to const traits now that it has an open RFC
- edec592e71f1346db1be92aff99162ac6fc69e6a
- Fixed a broken link
- 19469dc0520706fa99eeb01379dcb58b4c553f61
- Fixed broken indentation on a bullet list
- 0f9ec849ab44c73bd07b16768f7580568134aade
These are the alternatives described in the RFC that I think are worth consideration as the primary proposal:
- Using
?Traitsyntax instead of positive bounds as per "Adding?ValueSized"
Since there seems to be consensus on it, I've adopted the alternative for replacing ValueSized with MetaSized and included this in the document. It just makes sense as it matches the current ?Sized semantics.
Edit: oops, I see that thin CStr is mentioned.
What about thin CStr? Please, mention it in RFC. It is somewhat unique, because it has a size, but to determine size, we should read actual data, and thus size_of_val_raw is always unsafe. See https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/CStr.20as.20thin.20pointer/near/405436807 , https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/CStr.20as.20thin.20pointer/near/405473727 , https://rust-lang.zulipchat.com/#narrow/channel/219381-t-libs/topic/CStr.20as.20thin.20pointer/near/405518769 .
And I absolutely want to be able to use thin CStr as a last field of a struct, because this will finally solve long-standing dirent problem on Linux, which currently requires this horrible hack in standard library: https://github.com/rust-lang/rust/blob/c1132470a6986b12503e8000e322e9164c1f03ac/library/std/src/sys/pal/unix/fs.rs#L730-L768
Update 2025-02-03: in fact, we can support dirent two different ways: by adding thin CStr and by allowing embedding size of struct to struct itself. See https://github.com/rust-lang/rfcs/pull/3729#issuecomment-2630484541 for details
Wow, a funny (but good!) feeling to think that this might finally get resolved after a decade. :)
Instead of introducing a new marker trait,
std::ptr::Pointeecould be re-used if there were some mechanism to indicate that associated types or methods could only be referred to with fully-qualified syntax. Alternatively, it would be possible to introduce forward-compatibility lints in current edition, the new traits were introduced in the next edition and the edition migration previously described in the next next edition.
I think std::ptr::Pointee should definitely be reused. I am not sure which alternative is, but it seems to me like the right thing to do is:
- Use
std::ptr::Pointee - Do the hack to avoid new ambiguity in the current addition
- Remove the hack in the next addition
Also, I agree with @RalfJung than the ? avoidance is quite confusing, and we are mixing up syntax and semantics. The bottom line is that semantically, the trait hierarchy is the free lattice over the trait partial order. Decoding the complex math speak: that means the minimum element (or maxiumum, whatever way you want the arrows to point) is not a trait but the empty set of traits. So we need to specify what that means.
After we do that, we we can debate syntax.
In particular, the "Why have Pointee?" is a bit misleading in that semantically there currently is indeed no reason, it is just there for syntactic purposes.
However, if we reuse std::ptr::Pointee then there is a semantic reason, namely the associated type. ({} / no traits has no associated types or any other trait members, because it has no traits!) So here is an extra incentive to reuse std::ptr::Pointee --- one can side-step what @RalfJung and I are saying :).
At the point I still think it is good education to talk about the empty trait set as:
- You can't use it behind a pointer
- You can't use it as a value
- You could use it in
PhantomData, but probably this is left as future work - Maybe you can't quantify over it all (as opposed to you can, but then you can't use the variable anywhere, and then its an unused type parameter error)
Oh and a final thing on semantics, I might also also present the back compat / editions story this way:
- Old semantic hierarchy
- New semantic hierarchy
- mapping from old to new semantics, (old
{}(no traits) is mapped not to new{}but toconst MetaSized) --- in particular, do not speak of?Sizewhen describing this semantic mapping. - mapping from new syntax in next edition maps to new semantics.
In particular, the existing old syntax maps to the new semantics via the old semantics; we can cleanly factor that into those two steps, and I think this brings conceptual clarity.
- Use
std::ptr::Pointee- Do the hack to avoid new ambiguity in the current addition
- Remove the hack in the next addition
imo having an associated type on practically every type will be annoying, so I think it might be useful to require writing <T as Pointee>::Metadata instead of T::Metadata on all editions.
the trait's unstable, if it's just a matter of bikeshedding we can rename the type PtrMetadata or sth
I think
std::ptr::Pointeeshould definitely be reused. I am not sure which alternative is, but it seems to me like the right thing to do is:
- Use
std::ptr::Pointee- Do the hack to avoid new ambiguity in the current addition
- Remove the hack in the next addition
I've added this as one of the unresolved questions.
In particular, the "Why have Pointee?" is a bit misleading in that semantically there currently is indeed no reason, it is just there for syntactic purposes.
I've rewritten this section, it should have been updated earlier with the addition of the alternatives which keep the ?Sized syntax and clarified that it's just a syntactic difference.
At the point I still think it is good education to talk about the empty trait set as:
- You can't use it behind a pointer
- You can't use it as a value
- You could use it in
PhantomData, but probably this is left as future work- Maybe you can't quantify over it all (as opposed to you can, but then you can't use the variable anywhere, and then its an unused type parameter error)
Oh and a final thing on semantics, I might also also present the back compat / editions story this way:
- Old semantic hierarchy
- New semantic hierarchy
- mapping from old to new semantics, (old
{}(no traits) is mapped not to new{}but toconst MetaSized) --- in particular, do not speak of?Sizewhen describing this semantic mapping.- mapping from new syntax in next edition maps to new semantics.
In particular, the existing old syntax maps to the new semantics via the old semantics; we can cleanly factor that into those two steps, and I think this brings conceptual clarity.
I haven't made these changes at the moment - I've had good feedback about the explanations in the RFC and would prefer not to make major changes to that until the proposal itself needs changing.
I've updated the previous summary comment so it is still accurate.
I've pushed one small change with a reference to the now-upstream const traits RFC in #3762.
Linux has at its syscall boundary struct statmount. See here for details: https://brauner.io/2024/12/16/list-all-mounts.html . Its first field is size of whole struct itself. And it is u32 on all platforms! So, yes, I think we should support such structs. Note: this is not size of DST in its end, it is size of whole struct.
There is even more exotic case: struct dirent ( https://www.man7.org/linux/man-pages/man3/readdir.3.html ). (Yes, I already talked about it in previous comment, but I want to add more.) It embeds its own size, too. But not as a first field, but as a third. :) And that field (d_reclen) is not usize, it is u16! And again, this is not size of last DST field, this is size of struct itself.
Note: manpage says that size of last field is 256. This is a lie. In fact, this is DST, and it can be both bigger and smaller than 256.
Also, the string in the last field is always proper null-terminated C string, so we have two different ways of determining struct size: by calling strlen on d_name (with necessary calculations) and by reading d_reclen. So, technically d_reclen field is redundant. And to properly support this struct in Rust, Rust should have at least one of the following two features:
- ThinCStr we all dream about. It should be allowed to be located in the end of a struct (this will support this
d_namefield) - Embedding size of a struct (of a whole struct!) inside struct itself. Not necessary as a first field. And not necessary as a
usize.u16should be supported
Not supporting both features will lead to horrible hacks, such as this: https://github.com/rust-lang/rust/blob/c1132470a6986b12503e8000e322e9164c1f03ac/library/std/src/sys/pal/unix/fs.rs#L730-L768 (this is from standard library!)
And again: to support statmount we need possibility to embed size of struct inside struct itself. As a first field of size u32 (even on 64-bit platforms). In this case calling strlen on last field will not help, because it is allowed to contain many embedded null bytes
Not supporting both features will lead to horrible hacks, such as this:
In the latest version, this hack is mostly gone. What remains is not so bad: https://github.com/rust-lang/rust/blob/58d6301cad7ac20407e708cd9d1ec499d1804015/library/std/src/sys/pal/unix/fs.rs#L726-L753 (https://github.com/rust-lang/rust/pull/136479 cleans this up further by removing the macro.)
IMO it is not worth contorting the language to natively express esoteric types such as those, as long as we have some way of interfacing with C code using such types (and we do).
Another summary comment!
Here are the previous update summaries copied below so you don't need to uncollapse GitHub comments to find it:
2024-11-25
Summary comment: https://github.com/rust-lang/rfcs/pull/3729#issuecomment-2498703253
For those following along or catching up, these are the notable the changes to the RFC since this was posted:
- Clarify proposed behaviour for
?Traitsyntax for non-Sized, which is currently accepted- 23cb8a227e96452dc63eb78045f58bc259c66153
- Stop re-using
std::ptr::Pointeeand makePointeeits own new marker trait to avoid backwards incompatibility- 0c2f6e6016919faa39792c97a6dca6c435213939, 2831cca24c4db43b8197357bea5ccc4882f410a4
- Clarify backwards compatibility implications of
?Sizedsyntax and add alternatives to removing the default bound using positive bounds which continue to use?Sized- These are particularly valuable additions to the RFC as some of these alternatives are quite viable and have significant advantages
- 5f4b8ff938f94a7f4ae7a76d5a84bc35a219b772, ab8e7f6476aa594c31bdfdb4a7ee56b609f6c153, b050c2b48ebe6faeca0e612f4972afe8466151f0, 432a77aa18941bc3707b7eb20eb0413f0ae18ad1, 6e124e54a41680b580406eea04c887403010fa3c, 4faeb83062dd3e4b26a56338f811cd27f2e2d6cc
- Add that relaxing existing bounds in trait methods would be backwards incompatible
- b4258c7cd29a55dd54dac8bcccc1840e36dfeb9b
- Elaborate on necessity of implicit
const ValueSizedbound onSelftype of traits- 9158ebb0aa3865d6475b3df741632693d3f1d574, b71401c383b33559884b1940ef669276bb8ff29c, 5573be779fb281f04bacc1d9df38e5b670c1d25d
- Add
MetaSizedalternative toValueSizedwhich would resolve interactions with mutexes- c9e71bd21099ea8e0d84cfdc60baabff6eec740b, ef2f5cd86b9c750c5eadf691f1881ab40e2fe00a
- Clarified that bounds on return types can never be relaxed.
- 145446d995e091f034fba1c2f618aa4be3ac927b
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
- a840d8b1563645d4e233c8ec5df5c2288ac3bfb0, 260c980f07f2eed12572d5ba3c25cfbb37e6698d
- Removed HackMD's
rust=syntax from codeblocks- 95a1b7ddadf2649288bcc71aecba4c776261add8
- Fixed referring to the introduction of a
const Sizedtrait, but rather adding a const modifier to the existingSizedtrait- b670517d1eb1d5bd42076a91e8aadccf69352435
- Added some background/context on dynamic stack allocation
- b8ea88152b9fc71ebba58330b17cceda570b57f3
- Use current experimental const trait syntax
- a703feb0a2b492a0416a2d9bdd86d6d95bdcffbc
- Corrected incorrect syntax for traits
- fad04b0a6ab386256cfe06667fb8941196e7cfd4
- Listed all alternate bounds (adding
~const ValueSizedto a list of bounds that it was missing from)- 2fb3aaa63ab75bb37b707a4bf8a9003b34e47742
- Fixed bound in description of
size_of_valchanges- 397e474a2cf81ed7d67e28d17797f8138c26c9f8
- Corrected description of current
size_of_valandalign_of_valbehaviour- 6c1482bc9a4af453360da767310b5b5e2b52bf72
- Corrected description of extern type usage in structs
- 1f85898896a85602d146049726f63f70ee303ffd
- Mention Rust for Linux's interest in extern type
- 98af888300a66c0e25373c23077b9af139b06fc5
- Weaken language in the
externreffuture possibility to make it clear this proposal would not be sufficient on its own to support these- 60eab1ac8b46479d61e791384f9130ef9ff87100
- Re-write
Alignedfuture possibility so that it is clearAlignedcouldn't be added to the proposed hierarchy- 61f8d6dac96406a3f73f4adf11adce64ea3ec39c
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:
- Adding
MetaSized(either replacingValueSizedor in addition to it), as per the "What about MetaSized instead of or in addition to ValueSized?" section. - Using
?Traitsyntax instead of positive bounds as per "Adding?ValueSized"
2024-12-04
Summary comment: https://github.com/rust-lang/rfcs/pull/3729#issuecomment-2517204789
These are the major changes since the last summary:
- Change from
ValueSizedtoMetaSized- 72743b6f72817dd7d8659e67dd4da8b828f6d7aa, 57b9a857880e6d314425cc191e90c09b2e8d6997
- Add unresolved question about whether re-using
std::ptr::Pointeeis important.- d6d73b2ee594654e1c8ec05e37cec1ea4463bc60
These are the minor changes since the last summary:
- Clarify that bounds on parameters used as return types can never be relaxed (return types still need to implement
Sized)- 145446d995e091f034fba1c2f618aa4be3ac927b
- Clarify that non-const
Sizedis not nameable in the current edition due to the backwards compatibility migration, only in the next edition- b620534afeca9d9d469924227a43a3ad09bc0c4c
- Clarify which
Pointee(marker traitPointeeorstd::ptr::Pointee) is referenced in the Custom DSTs future possibility- 02d175949589b5a729eefd52f9cafba03b9fd38e
- Improve clarity of the table describing alternative syntax proposals for relaxing bounds
- 8cbaef99e3b49b5d81883382c01d2d8fab063f56
- Strengthen wording describing use of runtime-sized types in a const context as unsound
- 9fd3dffd95117fa622a6b9f23439bdf896d28611
- Expand on motivation for
MetaSized- 462d016a8f8bc00bf0ce6c10e8f52bcf0903cf87
- Specify that methods of the new traits would be backwards-incompatible too, not just associated types
- aa2145002948a1201201cf7026df2b52841f12e1
- Use the same indentation in code blocks throughout
- c0ee97dadf58a7eec3d2eb10df098b0af855b8d3
- Fix typo in list of when each trait gets implemented
- 7a11fe901b0d977e26ee7749b230f05c01ba53bd
- Add a concrete example of code that would break if a supertrait of
Clonewere relaxed- 762c6d87d0a844ac8f03ebd54c49a26de42d827e
- Added note about potential reasons why delaying relaxation of
size_of's bound might be desirable- 52b776f550853571e93b2014f3ada67e82c89589
- Fixed typo, replacing "alignment" with "size"
- 5d602fb4d2d5ea06201f60fe5160c6b86e70be16
- Rewrote "Why have a
Pointeetrait?" section to clarify that the trait is only necessary due to the proposed removal of?Sizedsyntax- f26784b30e288dfebd1f8178bddb8c4b1ee418c1
- Updated reference to const traits now that it has an open RFC
- edec592e71f1346db1be92aff99162ac6fc69e6a
- Fixed a broken link
- 19469dc0520706fa99eeb01379dcb58b4c553f61
- Fixed broken indentation on a bullet list
- 0f9ec849ab44c73bd07b16768f7580568134aade
These are the alternatives described in the RFC that I think are worth consideration as the primary proposal:
- Using
?Traitsyntax instead of positive bounds as per "Adding?ValueSized"
We had a design meeting with the language team yesterday (Feb 5th) which led to the changes described below, a rough summary:
- No significant concerns were raised with the proposal itself (i.e. the specific traits proposed, the edition migration proposed, etc)
- There was a clear consensus on some of the unresolved questions and no strong opinion on others (see 58060179e9c4ea38e4fd553facbc56f74419c7fe)
- t-lang would be okay with a experiment proceeding with this, but the preference of the const traits implementors is that no experiment take place while const traits' syntax is undecided, as this would increase the work they have to do when making any potential syntax changes requested by t-lang
- It is still unclear how to proceed with regards to the const traits dependency
- Further experimentation following the meeting (see ) has reinforced the necessity of the const traits dependency
- There is disagreement within the language team whether the not-yet-accepted const traits dependency blocks this from being accepted (without a possibility stabilisation w/out const traits stabilisation)
I've started an implementation of this - I've more-or-less finished implementing the non-const parts of the proposal, and will proceed with the const parts. It won't land upstream until const traits implementors are okay with it.
These are links to the compare with previous versions of the document (switch to the "Files changed" tab and then the rich diff):
- Changes since the pre-RFC version of this discussed at the first language team design meeting
- Changes since the version of this discussed at the second language team design meeting
- Changes since the 2024-11-25 summary comment
- Changes since the 2024-12-04 summary comment
These are the major changes since the last summary:
- Add note describing a niche but unavoidable backwards incompatibility
- 6533e108a1138dab3ad37ec17063ffef9827cf5d
- Note that const traits isn't a strict dependency
- 7b99ac6e22a4b0e1c244315769238936825beb5f (superseded by below)
- 4ba5b07099942ced287e222faa33025ed8be5189
- Describe the perspective of the language team following our meeting on the unresolved questions (leaving them unresolved but expressing a bias in a direction)
- 58060179e9c4ea38e4fd553facbc56f74419c7fe
- Document that non-const
Sizedtypes have the same properties asconst Sized- 544a788e3b909b5425a704c758b2efb047ebbae2
- Change implicit supertrait addition to be an edition migration
- f6c4ba6fcde8a51e05929ab71b715b2d7c100571
These are the minor changes since the last summary:
- Describe another alternative which would enable re-using
std::ptr::Pointer- bef745911f1ee6ab8311dbd1c3c98caf5965d19e
- Note that these traits can be stabilised independently of each other
- 96a70f92fb3a930bc61f3572ea0eabda36af33ce
- Mention that
Pointeecan be implemented as the absence of bounds- d3fd7e89d1fb37334757420883602ab731aeca2f
- Reword now that
?TraitforTrait != Sizedis an error- 9ca271bf8d99fb22561f760b298a9c971e6f2bca
- Clarify additive/subtractive behaviour in implied default bound removal w/ supertraits
- 410b312475c07f372081b56ec65ab2515f5b8c1c