3

Since .max() doesn't work for f64s, I'm writing a ForceOrd struct that asserts that the argument isn't a NaN. The intended usage is something like:

let m = xs.iter().map(|&x| ForceOrd(x)).max().unwrap().into();

However, I can't get the Into trait implementation to compile with the error:

conflicting implementations of trait `std::convert::Into<_>` for type `ForceOrd<_>`

The code (playground):

#[derive(PartialEq, PartialOrd)]
pub struct ForceOrd<X: PartialEq + PartialOrd>(pub X);
impl<X: PartialEq + PartialOrd> Eq for ForceOrd<X> { }
impl<X: PartialEq + PartialOrd> Ord for ForceOrd<X> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}
/// doesn't work
impl<X: PartialEq + PartialOrd> Into<X> for ForceOrd<X> {
    fn into(x: Self) -> X { x.0 }
}
/// doesn't work either
impl<X: PartialEq + PartialOrd> From<ForceOrd<X>> for X {
    fn from(x: ForceOrd<X>) -> Self { x.0 }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
yong
  • 3,583
  • 16
  • 32
  • Relaxing the generic constraints on this and directly implementing it on f64 should work? Is that not an option for you? I don't think its possible to add the trait bounds to an open generic across crates like you have (which should be the error you are getting if you implement _just_ `From`) – Simon Whitehead Oct 09 '16 at 08:05

1 Answers1

5

You can't have both From and Into implemented for a single type, i.e. you can't impl From<ForceOrd<X>> for X if you also impl Into<X> for ForceOrd<X>. You only need one, too. As the docs for Into and From both state:

From<T> for U implies Into<U> for T

You should probably go with just a From implementation. You can see the following question for information on which to pick in general: When should I implement std::convert::From vs std::convert::Into?

Edit: as implementing From is not (in this case) as trivial as just removing the impl Into, below you can see how this can be achieved for f64:

#[derive(PartialEq, PartialOrd, Debug)]
pub struct ForceOrd<X: PartialEq + PartialOrd>(pub X);

impl<X: PartialEq + PartialOrd> Eq for ForceOrd<X> { }

impl<X: PartialEq + PartialOrd> Ord for ForceOrd<X> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}

impl<X: PartialEq + PartialOrd> From<X> for ForceOrd<X> {
    fn from(x: X) -> ForceOrd<X> {
        ForceOrd(x)
    }
}

fn main() {
    let xs = vec![1.1f64, 3.5, 2.2];

    let max = xs.iter().map(|&f| <ForceOrd<f64>>::from(f)).max().unwrap();

    println!("{:?}", max); // prints "ForceOrd(3.5)"
}

Unfortunately I'm afraid this is as far as you can get; you won't be able to implement:

impl<X: PartialEq + PartialOrd> From<ForceOrd<X>> for X

to be able to do a final

<f64>::from(xs.iter().map(|&f| <ForceOrd<f64>>::from(f)).max().unwrap())

because f64 is not local to this crate. You can read more about this limitation in this very detailed blog entry by Niko Matsakis and see this question in StackOverflow.

Community
  • 1
  • 1
ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • I think the OP tried each individually. The issue is attempting to implement a trait where the generic type has trait bounds that aren't declared in the current crate. I don't think this is possible. Its possible in the standard library because thats where the original traits live. – Simon Whitehead Oct 09 '16 at 08:03
  • 1
    I expanded my answer with a solution to a case where there is only one `impl` in place. – ljedrz Oct 09 '16 at 08:30