I have some objects and they share some methods but all also have unique methods. As I need to store the objects in a list I have to use an enum for this but I can't find a way to implement methods on a variant so I have to use structs and then an enum to contain the structs. I'd like to be able to edit the contents of the enum generically but I'm getting a generic/trait issue that I don't understand
The arg in Wrapper::Foo(arg) has type Container<Foo>, and similar for Wrapper::Bar(arg)
Wrapper::mutate() takes an arbitrary type T: Something
Armed with these, consider the following scenario:
We have a value let w = Wrapper::Foo(Container { contents: Foo });.
We then call w.mutate::<Bar>(m) where m is a fn that returns Container { contents: Bar }.
On the one hand this would seem like it should type check: Bar: Something, so what's the problem?
The problem is that c is still of type Container<Foo>, and since you're trying to write a Container<Bar> in there you get those type errors.
A key point here is that all uses of a piece of generic code should be sound and valid, so if there's a counterexample like the one I constructed above, your code won't type check.
You might be confused as to what generics and type parameters are.
A generic type variable can only ever stand in for a single type in a specific instantiation of a generic type or function. In your usage, you request that it stand in for two different types. This is simply not possible.
One would need higher-rank trait bounds (HRTB) over types for this to work. Unfortunately, in today's Rust, HRTBs only exist over lifetimes. You can't have a single function-typed argument be instantiated with two different type parameters.
You are also confusing generics (universal quantification) with existential types. When you have a type parameter on your function, then the caller of the function can choose it. This means that it can be whatever the caller wants, as long as it satisfies the trait bounds. But this is not what you want. You don't want to let the caller choose the types – instead, you want the function implementation itself to choose the types.
Accordingly, it makes no sense to allow any caller-chosen type. Of course, a type variable that can stand in for an arbitrary type can't be assigned to places of type Foo or Bar – what if the caller supplies a type that is not Foo or Bar?
What you are trying to do here is not directly possible, overall.
in Rust. Unfortunately, the language does not have such features… yet…
The most flexible stable workaround would be to use a custom trait instead of the closures, but you’d lose the convenience of closures, with automatic variable capturing and such.