“Baseline bounds”: an extensible replacement for `?Sized`

would your proposed NotSized imply that a type should be Move ? That seems.. unideal.

@NotSized in particular (which, I reiterate, is a placeholder name) would mean the thing that ?Sized means today. Since, today, values of a ?Sized type can be moved (it’s just hard to actually perform that move), if there was a Move trait, it would necessarily be true that NotSized implies Move — and Sized does too. This is unavoidable to avoid breaking existing code that makes the assumption of movability.

In order to enable generic code to work with !Move types, we would need a new baseline trait to describe types that are both not-necessarily Sized and not-necessarily Move. Then, from that baseline, you can add Sized, Move, or both as you see fit. They are usable separately or together just like any other trait bounds.

More generally, core always has to provide a baseline trait which is “the least possible assumptions you can make about a type”, to enable users to add back further assumptions (bounds) one at a time. Any time we add a new way for types to be more restricted in usage (linear, immovable, truly unsized, …), we need a new “lower” baseline trait for new code to talk about working within those restrictions. Of course, it’s desirable to not have too many iterations of such lowering, but the point of baseline bound syntax is that such superseded traits only end up as extra library items, not extra language semantics. All older baselines should be expressible as blanket implemented traits (or trait-aliases) for some combination of the “latest” traits.


Perhaps it would help to write out the definitions we’d be working with, in a world where we have all the fun features; we might have core:: traits and trait aliases like:

#[lang = "ultimate_baseline"] // exempted from the "must have @ supertrait" rule
pub trait Baseline2030 {}

/// Types that can be moved to a new address.
/// Like `Send` and `Sync`, auto-implemented but also manually implementable.
pub unsafe trait Move {}

/// Types that can be dropped.
pub trait Affine {}

/// Types that have a size accessible at least by reading the value or metadata,
/// and possibly also statically.
pub trait ValueSize {/*...*/}

/// Types whose values all have the same size.
#[lang = "sized"] // this trait has the compiler magic the `Sized` trait currently does.
pub trait StaticSize: ValueSize {}

/// Identical in effect to today's implicit or explicit `T: Sized`.
pub trait Sized = @Baseline2030 + Affine + Move + StaticSize;
/// Identical in effect to today's explicit `?Sized`.
pub trait NotSized = @Baseline2030 + Affine + Move + ValueSize;

Every possible set of properties can be expressed as a bound @Baseline2030 + ..., but some of them also have other names. (I’m not proposing to actually name a trait Baseline2030 except perhaps in the library internals; we’d probably want to give them more meaningful names. Having to come up with such names is one of the disadvantages of this proposal.)

1 Like