> std::iter::Iterator<Item = Rc<dyn AnimalT>>

use std::rc::Rc;

pub trait AnimalT {
    fn foo(&self) ;
    
}

fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
    todo!()
}

fn main() {
    println!("Hello, world!");
}

Whny does this code not compile? Surely the size of Rc<dyn AnimalT> is known at compile time.

The size that is not known is that of the Iterator, not the Rc.

1 Like

Let me go through the compiler output to help you figure out these sort of questions for yourself in future:

warning: trait objects without an explicit `dyn` are deprecated
 --> src/main.rs:8:13
  |
8 | fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>`
  |
  = note: `#[warn(bare_trait_objects)]` on by default

Here, it tells you that it interpreted the return type as the old (pre-dyn) trait object syntax, and suggests you replace it with dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>.

error[E0746]: return type cannot have an unboxed trait object
 --> src/main.rs:8:13
  |
8 | fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
  |

dyn Iterator doesn’t have a known size, though (it needs to be boxed or similar), so you need to change the return type. The compiler provides three suggestions:

help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
  |
8 | fn foo() -> T {
  |             ^

Option 1 is to name the particular object that you’re constructing, instead of one of the traits that it implements.

help: use `impl std::iter::Iterator<Item = Rc<dyn AnimalT>>` as the return type if all return paths have the same type but you want to expose only the trait in the signature
  |
8 | fn foo() -> impl std::iter::Iterator<Item = Rc<dyn AnimalT>> {
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Option 2 is to use impl Trait syntax to return the same object you would have for Option 1, but only allowing callers to access Iterator methods.

help: use a boxed trait object if all return paths implement trait `std::iter::Iterator<Item = Rc<dyn AnimalT>>`
  |
8 | fn foo() -> Box<dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>> {
  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Option 3 is to use dynamic dispatch, and put the trait object in a Box so that it’s Sized and thus a valid return type.

2 Likes
  1. I am definitel at fault for not reading the highly helpful compiler error messages rustc generated.

  2. If we look at:

use std::rc::Rc;


pub trait AnimalT {
    fn foo(&self);
}

pub struct Bar {}

impl Bar {
    fn bar() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
        todo!()
    }
}

fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
    todo!()
}

fn main() {
    println!("Hello, world!");
}

We get error message of:

warning: trait objects without an explicit `dyn` are deprecated
  --> src/main.rs:11:17
   |
11 |     fn bar() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

warning: trait objects without an explicit `dyn` are deprecated
  --> src/main.rs:16:13
   |
16 | fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `dyn`: `dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>`

error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = std::rc::Rc<(dyn AnimalT + 'static)>> + 'static)` cannot be known at compilation time
  --> src/main.rs:11:17
   |
11 |     fn bar() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = std::rc::Rc<(dyn AnimalT + 'static)>> + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
   = note: the return type of a function must have a statically known size

error[E0746]: return type cannot have an unboxed trait object
  --> src/main.rs:16:13
   |
16 | fn foo() -> std::iter::Iterator<Item = Rc<dyn AnimalT>> {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
help: use some type `T` that is `T: Sized` as the return type if all return paths have the same type
   |
16 | fn foo() -> T {
   |             ^
help: use `impl std::iter::Iterator<Item = Rc<dyn AnimalT>>` as the return type if all return paths have the same type but you want to expose only the trait in the signature
   |
16 | fn foo() -> impl std::iter::Iterator<Item = Rc<dyn AnimalT>> {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: use a boxed trait object if all return paths implement trait `std::iter::Iterator<Item = Rc<dyn AnimalT>>`
   |
16 | fn foo() -> Box<dyn std::iter::Iterator<Item = Rc<dyn AnimalT>>> {
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

i.e. we get the helpful message in the "pub fn foo()" case, but not in the "fn Bar::bar()" case

This is what threw me off. After I refactored to a minimal failure case, I saw taht it generated the same error, but did not realize their was followup suggestions.

Ah, you should submit a bug report that the help message didn't show up in both cases.

1 Like