Requirement to know size at compile time

Is it correct that all of these need to have sizes known at compile time?

  • array items
  • tuple items
  • Vec items
  • HashSet items
  • HashMap keys and values

IIUC, in order to put items whose sizes are not known at compile time into these, one approach is to put each item in Box.

Assuming all of this is true, what is it in the documentation for these types that tells me this?
For example, I don't see anything about it here: array - Rust

Most often you'll see it documented the other way, where T: ?Sized meaning the size doesn't need to be statically known. That's what the docs for Box<T> say, at least if you expand "Show declaration".

1 Like

There’s an exception to this one: What the compiler really needs to know is the byte offset of each field, which only requires the previous fields to be Sized. So the last item of a struct or tuple can be dynamically sized, which makes the whole type dynamically sized as well.

1 Like

Nothing. By default, types are assumed to be sized in generic bounds. You can opt out using ?Sized if necessary, so you will know when something special is happening.

As to whether or not a type is sized: it's not in the documentation of types, either; it's pretty much in the language specification. The following types are unsized:

  • slices ([T], i.e. when not behind a reference or pointer)
  • String slices (str, OsStr) and Path
  • Trait objects (dyn Trait), again, when not behind a pointer
  • structs and tuples of which the last field is an unsized object.

Everything else is sized. (Did I miss something in the list above?)

2 Likes

To add context on this one, this is a currently unstable feature (unsized_tuple_coercion). Also, the same rules apply for structs, but I guess they're also kinda unstable.

They're pretty much a special case of the first point since they're wrappers over a slice (generally [u8])

3 Likes

That might very well be the case!

(I just never cared enough about them to look up their actual definition, and the std documentation only shows source code for immediate non-private modules, whereas e.g. OsStr has some intermediate modules for abstracting over platforms, so it's not apparent how it's implemented. And given the recent tendency of generously making many std types into lang items, I wouldn't be surprised if OsStr and Path were special-cased as well… Plain str is, however, a separate primitive type on its own right.)

I did a quick check on stable that &(usize, dyn Debug) wasn't rejected as a function argument, but I never attempted to actually construct one. It sounds like this is a bit in limbo, where the type's existence and behavior is stable but there's not currently a way to actually construct one.

Bit of a niche, but extern types are unsized (or will be).

1 Like

And it may be worth noting that OsStr and Path are just examples of "structs and tuples of which the last field is an unsized object," not built into the compiler in the way that str and [T] are.

2 Likes