Rustlings traits4.rs Why impl Trait syntax works but trait bound syntax or where clause does not work

Viewed 30

I'm doing Rustlings course traits4.rs exercise. The task is basically choose the correct signature for compare_license_types function. Using the impl Trait syntax as below works well:

pub trait Licensed {
    fn licensing_info(&self) -> String {
        "some information".to_string()
    }
}

struct SomeSoftware {}

struct OtherSoftware {}

impl Licensed for SomeSoftware {}
impl Licensed for OtherSoftware {}

fn compare_license_types(software: impl Licensed, software_two: impl Licensed) -> bool
{
    software.licensing_info() == software_two.licensing_info()
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn compare_license_information() {
        let some_software = SomeSoftware {};
        let other_software = OtherSoftware {};

        assert!(compare_license_types(some_software, other_software));
    }

    #[test]
    fn compare_license_information_backwards() {
        let some_software = SomeSoftware {};
        let other_software = OtherSoftware {};

        assert!(compare_license_types(other_software, some_software));
    }
}

If I change the function signature to use trait bound syntax or where clause, it no longer compiles:

fn compare_license_types<T: Licensed>(software: T, software_two: T) -> bool {}
// Or
fn compare_license_types<T>(software: T, software_two: T) -> bool
where T: Licensed {}

Both fail with compile error:

error[E0308]: mismatched types
  --> exercises/traits/traits4.rs:37:54
   |
37 |         assert!(compare_license_types(some_software, other_software));
   |                                                      ^^^^^^^^^^^^^^ expected struct `SomeSoftware`, found struct `OtherSoftware`

error[E0308]: mismatched types
  --> exercises/traits/traits4.rs:45:55
   |
45 |         assert!(compare_license_types(other_software, some_software));
   |                                                       ^^^^^^^^^^^^^ expected struct `OtherSoftware`, found struct `SomeSoftware`

What am I missing here?

1 Answers
fn compare_license_types<T: Licensed>(software: T, software_two: T) -> bool { ...

tells the compiler that both software and software_two have type T, where T can be any type implementing Licensed. When you pass in some_software which has type SomeSoftware, Rust infers that T must be type SomeSoftware. But the parameter software_two also has type T, i.e. type SomeSoftware. But you're passing it an argument of type OtherSoftware. That's why it doesn't compile.

You can fix this by making compare_license_types generic over two distinct types that both implement Licensed:

fn compare_license_types<T: Licensed, U: Licensed>(software: T, software_two: U) -> bool { ...

which is what the impl Trait syntax does implicitly.

Related