0

This is a simplified version of the issue I am currently facing.

trait SuperObject {
    fn object_name(&self) -> String;
}

trait Inspect {
    fn inspect(&self);
}

impl Inspect for SuperObject {
    fn inspect(&self) {
        println!("I am a Superobject.");
    }
}

struct Object {
    name: String
}

impl SuperObject for Box<Object> {
    fn object_name(&self) -> String {
        format!("I am {}.", self.name.clone())
    }
}

struct ObjectPool {
    object1: Box<Object>,
    object2: Box<Object>,
    object3: Box<Object>
}

impl ObjectPool {
    pub fn new() -> ObjectPool {
        ObjectPool {
            object1: Box::new(Object { name: String::from("Object 1") }),
            object2: Box::new(Object { name: String::from("Object 2") }),
            object3: Box::new(Object { name: String::from("Object 3") })
        }
    }
    fn all_objects(&self) -> Vec<&SuperObject> {
        let mut ret: Vec<&SuperObject> = Vec::new();
        ret.push(&self.object1);
        ret.push(&self.object2);
        ret.push(&self.object3);
        ret
    }
}

fn main() {
    let objectpool: ObjectPool = ObjectPool::new();
    let allobjects: Vec<&SuperObject> = objectpool.all_objects();
    for i in &allobjects {
        println!("{}", i.object_name());
        // Comment the following line in order to drop error E0597
        i.inspect(); // FIXME: borrowed value must be valid for the static lifetime
    }
}

The error when attempting to compile this snippet is as follows:

error[E0597]: `objectpool` does not live long enough
  --> src/main.rs:50:41
   |
50 |     let allobjects: Vec<&SuperObject> = objectpool.all_objects();
   |                                         ^^^^^^^^^^ does not live long enough
...
56 | }
   | - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

error: aborting due to previous error

After numerous searches, from what I understand, the objects being instantiated have a default static lifetime, as referred in https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html

I believe the output of ObjectPool's all_objects method is elided by the compiler as static as is evidenced by one of the errors evoked when I attempted to debug the snippet:

error[E0308]: mismatched types
  --> src/main.rs:42:18
   |
42 |         ret.push(&self.object2);
   |                  ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found reference
   |
   = note: expected type `std::boxed::Box<SuperObject>`
              found type `&std::boxed::Box<SuperObject + 'static>`

What would be the best course of action this doesn't involve scrapping the object pool altogether? Or is there a more elegant abstraction befitting for rust implementations?

John N.
  • 25
  • 4

1 Answers1

3

The issue is your impl Inspect for SuperObject. Implementing a trait for another trait does not do what you expect from it. Basically the rule is: never do it. Essentially it means that only when you have a &(SuperObject + 'static), you'll be able to treat it as an Inspect. What you want is

impl<T: SuperObject + ?Sized> Inspect for T {
    fn inspect(&self) {
        println!("I am a Superobject.");
    }
}
oli_obk
  • 28,729
  • 6
  • 82
  • 98
  • Okay, I need to brush up on generics then. In the above solution, the Inspect implementation is now only permissible for SuperObject. For instance, if I were to try to use Inspect for structs other than SuperObject (e.g., OtherSuperObject) , that is not feasible. Is that right? Is there a workaround in this case? – John N. Oct 23 '17 at 22:04
  • Yea that's problematic. I'm not sure how to fix that. But usually I've noticed in such situations that I'm trying to force a polymorphic design on Rust and got everything to work after reworking the design in a rusty way – oli_obk Oct 24 '17 at 06:29