Type parameter not unconstrained error

I am trying to implement a generic from trait for my struct VecStorage.

Here is my code: all functions are only dummy functions for this example.

The code doesn't compile given U and I

not constrained by the impl trait, self type, or predicates

Can someone explain to me (i) what this means in this case and (ii) how I could fix this.

thanks!

trait El {
    fn to() -> usize;
}


type F = f64;
type I = i64;

impl El for F {
    fn to() -> usize {
        1
    }
}
impl El for I {
    fn to() -> usize {
        2
    }
}

trait OEl {
    fn odo() -> usize;
}

type Of = Option<f64>;

impl OEl for Of {
    fn odo() -> usize {
        3
    }
}

type Oi = Option<i64>;

impl OEl for Oi {
    fn odo() -> usize {
        4
    }
}
trait Vector{
    fn len(&self) -> usize;
}

type Floats = Vec<Of>;

impl Vector for Floats {
    fn len(&self) -> usize {
        8
    }
}

type Ints = Vec<Oi>;

impl Vector for Ints {
    fn len(&self) -> usize {
        5
    }
}

#[derive(Debug)]
struct VecStorage<T: Vector> {
    data: T,
}

impl<T: Vector, U: El, I: OEl> From<&str> for VecStorage<T> {
    fn from(vs: &str) -> VecStorage<T> {
        let res: Vec<I> = vs.split(" ").map(|x| 
            {
                match x.parse::<U>() {
                    Ok(x) => Some(x),
                    Err(_) => None,
                }
            }
        ).collect();

        VecStorage{
            data: res,
        }
    }
}

If I fully specify the generic parameter on both From and Vec Storage<T>, then I should be able to call from no matter what, but in your case there are still additional choices to make. Perhaps you should use a generic function instead of a trait?

Thx for your swift reply. Great community for newbies like me!

What do you mean with "Fully specify".

I will try a generic function instead.

The impl header must constrain all type parameters.

                            // \/ header starts here
impl<T: Vector, U: El, I: OEl> From<&str> for VecStorage<T> { ... }

This doesn't even mention U or I in the header, so they are unconstrained.

Some examples,

impl<T> Foo<T> for Bar { ... }
impl<T> Foo for Bar<T> { ... }
impl<T, U> Foo for Bar<T> where T: Yam<Rat = U> { ... }

all of these constrain T and U

In the last one, U is constrained because of the following deductions

  • U is an associated type on a trait constraint on T
  • T is constrained

So no matter what choice of T you have, there will only be 1 choice of U.

Note: the following do not constrain T

impl<T> Foo for Bar { ... }
impl<T, U> Foo for Bar<U> where U: Yam<T> { ... }

With the last one, U could implement Yam<_> with multiple different type parameters, so we don't have a guaranteed single way to constrain what T could be.

1 Like

Thanks for your detailed response. Unfortunately, I am a bit lost now and questioning my overall approach now.

As @alice suggested, I will try a generic function.

However, in order to increase my understanding of Rust's Traits I was also wondering if my initial attempt can be fixed.

What I want to achieve is building VecStorage from &str for the following types:

VecStorage<Floats> and VecStorage<Ints>; here I use T = Trait Vector

Given Floats and Ints contain Vec<Option<f64>> and Vec<Option<i64>> I created two other Traits

  • EL implemented for type F (=f64) and I (=i64)
  • OEl implemented for type Of (=Option<f64>) and Oi (=Option<i64>)

How do I include this into the header of my From Trait?

I played around with it (getting rid of I) ,but I am not sure how to include U in my header correctly?

The below function doesn't compile because of unexpected type argument. But how do I specify this then?

impl<T: Vector, U: El> From<&str> for VecStorage<T> where T: Vector<Vec<Option<U>>> {
    fn from(vs: &str) -> Self {
        let res: T = vs.split(" ").map(|x| 
            {
                match x.parse::<U>() {
                    Ok(x) => Some(x),
                    Err(_) => None,
                }
            }
        ).collect();

        VecStorage{
            data: res,
        }
    }
}

Any help regarding the specific question and my general approach are much appreciated!

Thanks

Fundamentally the problem is that for each choice of T the type VecStorage<T> may only implement the trait From<&str> once, however it will implement that trait several times: one time per choice of U.

Note that the T: Vector<Vec<Option<U>>> constraint does not save you. There's nothing saying that T couldn't implement Vector<Vec<Option<i32>>> and Vector<Vec<Option<String>>> at the same time. (you need associated types for that)

1 Like

Thanks. Understood.

So does this mean that my approach is not possible at all?

Because even if I used associated types I would have to specify two types:

trait From {
     type T // in implementation either Floats or T = Ints
     type U // in implementation `f64` if T = Floats and i64 for Ints
}

Yeah you can only have one when using associated types. I recommend just not going for a trait.

Thanks for your patience!

I guess I will try the approach using a generic function then.

Thanks!

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