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).

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