Why the last type need to be `?Sized`?

std::cmp::Ord

impl<A, B, C, D, E, F, G, H, I, J, K, L> Ord for (A, B, C, D, E, F, G, H, I, J, K, L)
where
    A: Ord,
    B: Ord,
    C: Ord,
    D: Ord,
    E: Ord,
    F: Ord,
    G: Ord,
    H: Ord,
    I: Ord,
    J: Ord,
    K: Ord,
    L: Ord + ?Sized, 
1 Like

It's less that it needs to be, and more that it can be. ?Sized is simply relaxing a restriction - all the other things need to be sized, but the last one doesn't.

As for why, I believe this is because structs, tuples, etc, can contain an unsized type, but they can only contain one, and it must be the last field/item in the struct/tuple. When a type is unsized, it will take up, well, a number of bytes that are undetermined at compile time. For instance, in &[u8], [u8] is unsized - it will take up 1 * length_of_slice bytes.

A tuple &([u8], [u8]) can't exist (and similarly, &([u8], u32), etc.), because there are two unsized things here - and the compiler wouldn't know how many bytes to offset to reach the second field. So, it doesn't make sense to implement traits for (T, U) with T: ?Sized.

But &(u32, [u8]) technically can exist - if all types but the last are sized, then it "works". The type (u32, [u8]) is then unsized itself, but all fields have a known offset. It's incredibly hard to actually make one, but the compiler allows them to exist.

So, this impl allows for that. The last type in the tuple may be an unsized type, while all the others must be sized. Hopefully that clears it up? There's more info at https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait.

12 Likes

Thanks.
But Is possible to make a tuple which contains a ?Sized field?

1 Like

Yes. As long as it's the last field as mentioned by @daboross due to the unsizedness.

It just occured to me you meant how to create a tuple, like a value, not a type.

Now I know it's possible in logical. But any example?

// doesn't have a size known at compile-time
let _ = (0, *vec![0]);

It appears that this might be made available through means similar to Unsize coercion for generic types (see last bullet).

#![feature(unsized_tuple_coercion)]

fn main() {
    let x: (u8, [(); 5]) = (0, [(); 5]);
    let x: &(u8, [()]) = &x;
}
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.