TIL: Arrays don't deref into a slice

Apparently arrays ([T; N]) don't implement the Deref and DerefMut traits. Instead, it looks like the compiler inserts some magic so a &[u8; 42] will coerce to &[u8]... But at the same time some ([T; 0] to [T; 32] or so) arrays implement AsRef<[u8]>?

Does anyone know why this is the case? I would have thought arrays are such an integral part of the language that the compiler could hard-code these trait definitions, even if true const generics aren't implemented/stable yet.

(playground)

For context, I encountered this when trying to implement a combinator similar to futures::join_all() that's backed by an array who's length is determined at compile-time by the number of items passed in.

Just a shot in the dark but could FixedSizeArray and Unsize<[T]> have something to do with this? (Not terribly familiar with compiler internals myself, so maybe it's a red herring.)

Taking a reference is the opposite of dereferencing, so it wouldn't make much sense for arrays to implement Derefor DerefMut.

This is related to CoerceUnsized trait. Standard library contains the following implementation:

impl<'a, 'b: 'a, T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}

This refers to Unsize trait. There is a hardcoded implementation of Unsize<[T]> for [T; N] (provided by the compiler, not standard library).

Those traits aren't stable, but their effects are visible even in stable Rust.

4 Likes

Of course, there's also the matter that arrays support a[i] and a.len() and etc., which cannot be explained by coercions. This must also be hardcoded to "behave like" auto-deref.

Why not? Indexing as well as .len() exists on slices.

Because coercions (even other Unsize coercions) don't enable behavior like auto-deref. (e.g. you can't call &dyn Any methods on &T)

3 Likes

That was my train of thought. The way arrays currently work feels just like it derefs to a slice (i.e. the auto-deref behaviour).

It looks like @xfix might be onto something with the Unsize trait. This is what the nomicon says about it:

Unsize is only implemented automatically, and enables the following transformations:

  • [T; n] => [T]
  • ...