Generics and Inference problem

Hi Rustaceans,

I'm trying to implement (for learning purposes) 2D vector in homogeneous coordinates.

#[derive(Debug, Copy, Clone)]
pub struct Vector2D<T> {
    pub x: T,
    pub y: T,
    pub w: T,  // 0 or 1. 0 = Non translatable.
}

I'm trying to provide a a new() method with only 2 parameters, as w, can only take two values (0 or 1). I want new(..,..) to build a 2D vector with x,y, and 1.

For this I created an Identity trait:

pub trait Identity {
    type Output;
    fn one() -> Self::Output;
}

I implement this trait for few basic types:

impl Identity for f64 {
    type Output = f64;

    fn one() -> Self::Output {
        1.0_f64
    }
}

Now my problem arise. When I try to implement my new() method:

impl<T> Vector2D<T> where
    T: Identity<Output=T>
{
    // Create Vector from values.
    pub const fn new(x1: T, y1: T) -> Self {
        Vector2D { x: x1, y: y1, w: Identity::one() }
    }
}

I got the following error:

   --> src/vector.rs:110:37
    |
110 |         Vector2D { x: x1, y: y1, w: Identity::one() }
    |                                     ^^^^^^^^^^^^^ cannot infer type
    |
    = note: cannot satisfy `_: Identity`

I cannot figure out how to use Identity::one() as parameter. I also don´t understand the note. Can anyone explain me what I'm doing wrong ?

Regards

Simple fix: T::one() or <T as Identity>::one()

Note: the function new is not a const fn anymore, if you make it a const fn, you'll get a error:

error[E0015]: cannot call non-const fn `<T as Identity>::one` in constant functions
2 Likes

Alternatively, remove the Output associated type from Identity and return Self instead:

2 Likes

This is the compiler telling you that there may be many types which implement Identity<Output=T>, and it can’t figure out which implementation you want it to use. To clear the error, you need to either specify the type explicitly (per @vague) or restrict the trait so that only one type can possibly implement it (per my solution above).

Many thanks all of you for your help. I realize that I really need to dig a lot more:

For me:

pub trait Identity {
    fn one() -> Self;
}

is Identical to:

pub trait Identity {
    type Output;
    fn one() -> Self::Output;
}

But it's not ... Going back to the book :slight_smile:

To illustrate the problem a bit, what value should x take in this example? There’s no way for the compiler to decide between 1 and 0.

struct Additive;
struct Multiplicative;

impl Identity for Additive
{
    type Output=i32;
    fn one()->i32 { 0 }
}

impl Identity for Multiplicative
{
    type Output=i32;
    fn one()->i32 { 1 }
}

fn main() {
    let x:i32 = Identity::one();
    // …
}

Ok, nice illustration :wink:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.