[Solved] Understanding unsized associated types

Very beginner question: I'm building a simple system where many models expose a common interface by impl some Model trait, which among other things has a fn to return an appropriate model controller. Here's pseudocode of a version that works:

pub trait Model {
    type Controller;

    ...

    fn controller(foo: bool) -> Option<Self::Controller>;
}

// And then in each model module...

struct MyModel;

impl Model for MyModel {
    type Controller = Arc<Mutex<MyModelController>>;

    ...

    fn controller(foo: bool) -> Option<Self::Controller> {
        if foo {
            Some(Arc::new(Mutex::new(FooMyModelController {})));
        } else {
            ...
        }
    }
}

trait MyModelController {
    ...
}

struct FooMyModelController {}

impl MyModelController for FooMyModelController {
    ...
}

This works. The issue is that I'd much rather set MyModel::Controller to MyModelController directly and have the controller method return Option<Arc<Mutex<Self::Controller>>> so that I can compose trait requirements (e.g., have it instead return Option<Arc<Mutex<Self::Controller + SomeOtherCommonTrait>>>). If I change the associated type from the Arc<Mutex<T>> to just the trait and change the return types, however, rustc complains:

error[E0277]: the trait bound `datatype::blob::ModelController + 'static: std::marker::Sized` is not satisfied
 --> src/datatype/blob.rs:6:6
  |
6 | impl super::Model for Blob {
  |      ^^^^^^^^^^^^ `datatype::blob::ModelController + 'static` does not have a constant size known at compile-time
  |
  = help: the trait `std::marker::Sized` is not implemented for `datatype::blob::ModelController + 'static`
  = note: required by `datatype::Model`

even though I am only using the associated type to parameterize Option<Arc<Mutex<...>>>. It doesn't seem like this associated type would need to be sized if I'm only ever referring to it through Arc/Mutex/etc., but I certainly don't grok most of the type system at this point. I've been using rust for awhile for simple CLI scripts and computation libraries, but moving to writing large, structured programs has been another quantum leap of figuring out that patterns from C++/java may not work.

Am I misunderstanding the problem? Is there an alternative way to declare the controller trait associated to the model? Is this whole approach unidiomatic?

Also, is this the appropriate venue for disposable questions like these that are a bit too long to ask in beginner's IRC?

Associated types are Sized by default. Have you tried:

trait Model {
   type Controller: ?Sized;
...
}
4 Likes