Impl Specialization for Concrete Types on a Generic Struct?


#1

Lets say I have the following:

  • A trait called Tray.
  • A second trait called Troy.
  • A struct called Stu.
  • An object in Stu that requires a generic type T that impls Tray.
  • A type that implements both Tray and Troy called Tob, and has its own generic type L.

And this signature for the struct declaration:

pub struct Stu<T: Tray + Troy> {
     foo: Thing<T>
}

impl<T: Tray + Troy> Stu<T> {
     pub fn bar(...) ...
}

impl<L: Thing> Stu<Tob<L>> {
    pub fn baz(...)...
}

I was reading the specialization RFC and it doesn’t seem to apply to this situation, and what I would particularly like is the ability to have methods generic over all T in the first impl, and some specialized methods in the Tob one. Particilarly I would like to call bar from inside baz, which I really don’t think is possible, but after reading all the documentation on impls and possibly using the specialization feature flag I just want to make sure it can’t work.

In the general case, its having a concrete type Tob that I want to have extra fields / do more things than the generic implementation, but still be able to compose the generic part with the specialized part rather than having both impls be distinct with all the methods and their bodies repeated (the differences are about ~30 locs in the project I’m working on, but the whole impl is 300 lines so doubling that is annoying).

The only way I can think to make that work right now is to have a private mod level function instead of impl methods that both impls call that contains common code in each impl block. Because this struct has a member with a generic on it it I can’t even have constructors without trait specialization (and the inner member type is from a third party crate).

The TLDR is if there is a syntactic way to invoke functions on a struct from a different impl block so long as the specialization holds (the caller is only a specialized form of callee).


#2

You’re right in that the specialization RFC doesn’t apply here because the specialization RFC (as far as I understand…lol) is about resolving conflicting implementations (of traits only, I think - not sure if inherent impls are covered).

The following (playground here) compiles on stable. Note I commented out a line that would have caused a compiler error since the function names were the same.

trait Tray{}
trait Troy{}

struct Stu<T: Tray + Troy> {
     foo: Box<T>
}

impl<T: Tray + Troy> Stu<T> {
     pub fn bar(&self){
     }
}

struct Tob<T>{
    inner: Box<T>
}

impl<L> Tray for Tob<L>{}
impl<L> Troy for Tob<L>{}

impl<L> Stu<Tob<L>>{
    pub fn baz(&self){
        self.bar(); //since Tob<L> implements Tray, Troy, self.bar() is available
    }
    
    //pub fn bar(&self){
    //}
}

#3

That does work! I was just worried about namespacing on the function definitions before I made all the changes.

Thank you so much!