Hello,
while looking a the implementation of std::error::Error
, I noticed the block impl From<String> for Box<dyn Error>
that piggy-backs on impl From<String> for Box<dyn Error + Send + Sync>
. This block was added due to String, From and Box<Error> interoperation could be better. · Issue #30156 · rust-lang/rust · GitHub.
Here is a toy program that recreates an equivalent problem:
trait Print: std::fmt::Display {
fn print(&self) {
println!("{}", self);
}
}
impl Print for i32 {}
impl From<i32> for Box<dyn Print + Send + Sync> {
fn from(x: i32) -> Self {
Box::new(x)
}
}
// Uncomment the following block to make this program compile.
// impl From<i32> for Box<dyn Print> {
// fn from(x: i32) -> Self {
// let x: Box::<dyn Print + Send + Sync> = From::from(x);
// x
// }
// }
fn main() {
let e1: Box<dyn Print + Send + Sync> = From::from(333);
let e2: Box<dyn Print> = e1;
e2.print();
let e3: Box<dyn Print> = From::from(123);
e3.print();
}
I think I understand why the line creating e3
does not compile without uncommenting the corresponding impl or changing it to
let e3: Box<dyn Print> = Box::<dyn Print + Send + Sync>::from(123);
But isn't the language a bit too strict here? Couldn't it see that although impl From<i32> for Box<dyn Print>
is not defined, there exists a conversion to Box<dyn Print + Send + Sync>
and that type coerces trivially to the required one? Would that be dangerous/problematic/limiting in any way?
The following discussion may contain the answer, but it's a bit too advanced for me to follow completely: