TryFromIntError Eq

Is it a good idea to allow the last line too?

#![feature(try_from, never_type)]
use std::convert::TryFrom;
use std::num::TryFromIntError;

fn main() {
    let x: u8 = 125;
    let y: Result<u32, !> = u32::try_from(x);
    let _ = y == Ok(125); // OK

    let x: u32 = 125;
    let y: Result<u8, TryFromIntError> = u8::try_from(x);
    let _ = y.ok() == Some(125); // OK

    let x: u32 = 125;
    let y: Result<u8, TryFromIntError> = u8::try_from(x);
    let _ = y == Ok(125); // Error
}

In general I find it useful to have errors that implement partial equality, but this is not a general rule or anything.
If you want that, you won’t be able to use TryFromIntError, but as a workaround you may be able to copy the source to your own crate, and then write an impl From<TryFromIntError> for MyTryFromIntError.

Combined with a PartialEq impl for MyTryFromIntError, that allows you to do this:

#![feature(try_from, never_type)]
use std::convert::TryFrom;
use std::num::TryFromIntError;

#[derive(PartialEq)] 
struct MyTryFromIntError(());

impl From<TryFromIntError> for MyTryFromIntError {
    fn from(err: TryFromIntError) -> MyTryFromIntError {
        MyTryFromIntError(())
    }
}

fn main() {
    // other stuff omitted

    let x: u32 = 125;
    let y: Result<u8, <MyTryFromIntError> = u8::try_from(x).map_err(MyTryFromIntError::from);
    let _ = y == Ok(125); // This is now perfectly fine
}

I use this pattern a lot for std::io::Error, which is rather lacking in trait support (and thus in usability).
This pattern also works for other traits like Serde’s Serialize and Deserialize, but as you move further away from derivable traits of course implementing it fully becomes more work.

Your code is OK, but what I was asking is if it’s a good idea to change the std library adding a the #[derive(PartialEq)] to std::num::TryFromIntError.

Personally I don’t see why not. Effectively the TryFromIntError struct is nothing more than a signal, the single nil field pretty much guarantees that. Therefore there’s no semantic ambiguity about what it means to compare 2 instances.

Of course I’m not a rustc core dev, so you’ll have to convince (one of) them to accept something like this.

1 Like

Hm, I was going to toss my nose up at this one, but after checking the stdlib, it turns out that a lot of Error types do implement Eq.

I am basically of the opinion that == should not be used on Result (as, in many cases, it simply cannot be), but seeing as the stdlib has already gone down this path, it’s best that it remain consistent.

I understand that this is the case on a practical level, but not why this should necessarily be the case other than the author not wanting those semantics?

When people see that it works sometimes, they wonder why it doesn’t work other times. I wouldn’t want to see a section appear in the Rust API Guidelines to “consider implementing Eq for error types, so that people can use == and assert_eq on Result.”. It’s better that people learn to use a match-based solution.

Sorry if my responses sound curt; both this and the prior one were written under a bit of a time constraint, so they are kind of raw.

Probably the closest analog is std::num::ParseIntError, which does impl PartialEq and Eq.

My guess is that TryFromIntError was kept intentionally to a minimum while still unstable, and that using equality checks for Result is an uncommon (IME) pattern.