Dynamic dispatch, which solves the issue you faced, needs to be explicitly opted into using the `dyn Trait` syntax, since it introduces a hidden indirection through a fat pointer.
This is definitely a difference from languages like Java or Python, where dynamic dispatch is the default (and sometimes there's no way to explicitly use static dispatch). On the other hand, languages like C and C++ also use static dispatch by default, with mechanisms like function pointers or `virtual` to provide dynamic dispatch as needed.
You would very likely have faced a similar problem in C++, had you used `auto x = (..) ? ... : ...`; (If you used `T x = ...; if (...) { x = ... } ...`, you'd have been faced immediately with the issue of "what type should T be" anyway, I think.)
I ran into that issue trying to port something else to rust, just didn't realize it was this same issue. In go you just define an interface and then make a slice of that interface and put things in it. In rust I ended up having to do
Vec<Box<dyn Checker>>
I think initially I tried just doing a Vec<Checker>
and when that failed I ended up putting something like "How do I make a vec of an impl in rust" and found a code sample.That's where the compiler just saying "The types don't match" is not very helpful.
https://play.rust-lang.org/?version=stable&mode=debug&editio...
error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
--> src/main.rs:5:12
|
5 | let y: Vec<dyn Display> = x.into_iter().collect();
| ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn std::fmt::Display`
error[E0277]: a value of type `Vec<dyn std::fmt::Display>` cannot be built from an iterator over elements of type `{integer}`
--> src/main.rs:5:45
|
5 | let y: Vec<dyn Display> = x.into_iter().collect();
| ^^^^^^^ value of type `Vec<dyn std::fmt::Display>` cannot be built from `std::iter::Iterator<Item={integer}>`
|
= help: the trait `FromIterator<{integer}>` is not implemented for `Vec<dyn std::fmt::Display>`
error[E0277]: the size for values of type `dyn std::fmt::Display` cannot be known at compilation time
--> src/main.rs:5:31
|
5 | let y: Vec<dyn Display> = x.into_iter().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `dyn std::fmt::Display`
I can see a bunch of places where we could improve the output that we haven't gotten to yet:- The third error shouldn't have been emitted in the first place, the first two are more than enough
- The first error has a note, but that note with a little bit of work could be turned into a structured suggestion for boxing or borrowing
- For the second suggestion we could detect this case in particular where the result would be !Sized and also suggest Boxing.
Edit: filed https://github.com/rust-lang/rust/issues/84346
It is also somehow unfortunate that `impl Trait` in locals isn't yet in stable, but once it is it would let you write `let z: Vec<impl Display> = x.into_iter().collect();`, but as you can see here, that doesn't currently work even on nightly: https://play.rust-lang.org/?version=nightly&mode=debug&editi...
https://play.rust-lang.org/?version=stable&mode=debug&editio...
so where it says
it could not be more unhelpful. I know those things are different, however the following "for i in output" works for both of those things individually, so why does it matter that the types are different since they both implement iteration?