Add `From<Box<[T; N]>> for Box<[T]>`

At the moment, Rust has a TryFrom<Box<[T]>> for Box<[T; N]> impl, but the reverse does not seem to work.

If we decide this is a good thing to add, I'd be happy to write it.

You can already convert a Box<[T; N]> to a Box<[T]> through unsize coercion (playground example)

4 Likes

I think a From impl would still be usefull when used in generics

You're right; Intellij Rust has led me astray. I'll file that as an issue there.

We aren’t having From implementations for Box<SomeType> to Box<dyn SomeTrait> either. Or for &[T; N] to &[T]. Adding From<Box<[T; N]>> for Box<[T]> might be a bit arbitrary.

2 Likes

I'd argue that conversion is reasonable as well.

The one thing that would put a stopper in all 3, though. IIRC [T;N] is a fundamental type, as is &T and Box, so the stdlib can't add a blanket impl for those conversions as a user crate could individually impl From<Box<[LocalType;N]>> for Box<[LocalType]>, and stdlib adding impl<T,const N: usize> From<Box<[T;N]>> for [T] would break that.

1 Like

No, arrays are not fundamental types, quite the opposite, they're always treated as foreign types, just like slices, so neither Box<[LocalType;N]> nor Box<[LocalType]> can be considered local, and that impl is impossible to write.

1 Like

Ah, that makes sense (otherwise, the TryFrom expansion couldn't happen). That should solve that problem, probably.

In any case, I think that more coercions should be available as a trait. In generic contexts it can be overly annoying to cause a coercion to happen. I had an issue when trying to validate the signature of fn-items before type-erasing them into a syscall array with a macro, in that I couldn't without writing the signature... Although I guess that From/Into wouldn't solve that issue, but my point stands. Coercing types in generic contexts requires forcing a coercion, and .from() is nicer than as ... or if true{x}else{something else that forces the coercion}. However, it may be better to add a Coercion trait that can be used to generically perform static coercions. That would also allow trait objects, which I know are local to the trait's crate, to receive these generic impls. It could also use an associated type, which is more useful in a generic context (as I do not believe that T: Into<U> allows inferring U).

1 Like

Don't we already have Unsize and CoerceUnsized?

A few reasons that isn't useful in this case:

  1. For the fn-item case specifically, that's not an unsizing coercion, though it would apply to the [T;N] case.
  2. CoerceUnsized and Unsize are unstable, and seem to be implementation details.
  3. CoerceUnsized has the same deficiences as Into, in that you can't infer the U in a generic context. It's also strictly worse, because there isn't (yet) a way to force it to perform the coercion without writing a cast or using if{...}else{...}.
1 Like

I think there's a reason coercions don't apply in generic contexted, and that's because it would be confusing to know what's the generic type. Yes, we already have autoref/autoderef that does something like that, and it has been proven to be confusing.

Also, CoerceUnsized is generic because it has to be. A non-generic version could work for [T; N], but not for trait objets, since Box<MyType> can be coerced to both Box<dyn Foo> and Box<dyn Bar> (if MyType implements Foo and Bar).

I guess that's true, so a non-generic would have to be something more like Decay, that's implemented for Pointers to Arrays, and fn-items to fn-ptrs, but not to trait objects. I still think it would be a good idea to have, because it gives even an explicit way to cause a coercion in a generic context. It may be difficult (to impossible) to allow implicit coercions in a generic context, but there should be a way to cause a coercion explicitly in such a context (even if you may not know the actual type you need to coerce to).