Specialization -- Mismatched Types

I'm trying to use specialization like this

#![feature(specialization)]
use std::marker::PhantomData;

struct Printer<T:Displayable>{
     phantom: PhantomData<T>,
}

struct Speaker();

struct NormalPrintable ();

struct SpecialPrintable {
    y : usize
}


trait Displayable{
    // elided methods for displaying a Displayable
}

impl Displayable for NormalPrintable{}
impl Displayable for SpecialPrintable{}

trait DisplayProducer<T:Displayable>{
    fn display(&self, t: T);
}

impl<T:Displayable> DisplayProducer<T> for Printer<T> {
    default fn display(&self, _t: T) { println!("Printing something printable"); }
}

impl DisplayProducer<SpecialPrintable> for Printer<SpecialPrintable> {
    fn display(&self, t: SpecialPrintable) { println!("SpecialPrintable is special: {}", t.y); }
}
impl<T: Displayable> DisplayProducer<T> for Speaker{
    fn display(&self, _t: T){
        // somehow display the Displayable acustically
        println!("What's that noise?");
    }
}


fn main() {
    Speaker().display(NormalPrintable{});
    Speaker().display(SpecialPrintable{y:3});
    
    Printer{phantom: PhantomData}.display(SpecialPrintable{y:3});

    // Uncommenting the next line leads creates an error
    // Printer{phantom: PhantomData}.display(NormalPrintable{});

}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=3a2d3b8cf01a0ff437dd049c71b2c18c

However, when I uncomment the commented line I get the following compile error

error[E0308]: mismatched types
  --> src/main.rs:50:44
   |
50 |      Printer{phantom: PhantomData}.display(NormalPrintable{});
   |                                            ^^^^^^^^^^^^^^^^^ expected struct `SpecialPrintable`, found struct `NormalPrintable`

With the min_specialization feature it's no different.

What can I do?

1 Like

I found two solutions to make it compile.

One is to add type argument to this PhantomData or Printer so that the compiler could infer the type correctly. Change

Printer{phantom: PhantomData}.display(NormalPrintable{});

into either of these:

Printer{phantom: PhantomData::<NormalPrintable>}.display(NormalPrintable{});
Printer::<NormalPrintable>{phantom: PhantomData}.display(NormalPrintable{});

Then it could compile & run normally.

Another way is to add an empty impl block for NormalPrintable:

impl DisplayProducer<NormalPrintable> for Printer<NormalPrintable> {}

IIUC possibly because of this statement from rfc#1210?

This default impl does not mean that Add is implemented for all Clone data, but just that when you do impl Add and Self: Clone , you can leave off add_assign ...

Not sure whether this is just because the feature is still unstable.

Thank you so much @robertking. My code (my real code not the playground) runs now.
Intellij shows me the correct type. I'd never guessed I need to tell the compiler explicitly. I just hope, we won't have to, when the feature gets stabilized.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.