= note: expected type `Rev<std::vec::IntoIter<_>>`
found struct `std::vec::IntoIter<_>`
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?
I think the key idea here is that Rust consistently uses static dispatch by default. When you invoke some method defined by a trait, it needs to look up at compile-time which actual implementation it should dispatch to. Since the if-else expression isn't returning the same type, it doesn't matter if they both implement Iterator -- Rust still doesn't know which actual type will be produced, so it won't be able to tell which method implementations should actually be dispatched to.
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.
I think the fundamental issue is that most languages these days use dynamic-dispatch invisibly and by default. Rust seeks to empower users to be more efficient by default (which is good), but sometimes, especially on this iterators case, it creates deeply confusing/frustrating barriers that have to be explicitly stepped around.
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.
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?