No Option/None comparison/unwrapping with embedded generics?

Hi everyone,

I basically have the following signature at hand:

fn test(&mut self) -> Result<Option<Vec<Vec<Field<Type<'static>>>>>, Error> {
    // branch 1
       Ok(Some(data)) // data is the ugly structure above
    // branch 2
       Ok(None) // Totally fine, under certain conditions the function doesn't return data
}

Now in a function test I wanted to check the branch that returns no data:

let res = x.test().unwrap();
assert_eq!(res, None);

However, the compiler notices an error as follows:

binary operation == cannot be applied to type std::option::Option<std::vec::Vec<std::vec::Vec<lib::Field<lib::Type<'_>>>>>

Apart from the fact that the argument itself is incredibly ugly and may be solved more elegant, I don't get why the error is encountered here. I'm assuming this is totally expected when not implementing/deriving corresponding trait functionality when expecting and comparing said data structure as returning option, but assuring None should be totally fine, no?

If anyone could enlighten me that would be awesome!

Most likely Field and Type need to implement Eq or PartialEq. For assert_eq you'll also need Debug trait so that the diff can be printed.

What is the full compiler error message?

For the None case you don’t need to use an equality test. You can just use assert!(matches!(res, None)), or (for the better error messages) use assert_matches!(res, None).

3 Likes

Good point about assert_matches !(res, None), didn't know about that one.

A side note, personally I avoid using assert!() since if it fails it doesn't tell you the actual value which more often than not provides details why something failed. In this case I'm not testing matches!() macro, I'm comparing expected and returned values of a function.

Most likely Field and Type need to implement Eq or PartialEq

Yes, this is true!

For the None case you don’t need to use an equality test. You can just use assert!(matches!(res, None))

Thanks, I also didn't know about this one!

That said, this indeed solves the problem (as it doesn't need that actual comparison).

Still curious what prevents the comparison. Relatively new to rust, so just wondering: Is this a general requirement to have all possible return values be comparable at compile time even for Option? Maybe I just falsely assumed that Option is an exception to this.

Yes.. well kinda yes. == actually belongs to PartialEq which does not need all values to be comparable. But indeed you can only use == on Option<T> if you can use it on T. Equality checks are a trait method like any other, there is no compiler magic in place to figure out “oh, it’s None, I know how to pattern match against that value instead of using PartialEq”.

Of course actual pattern matching still works without an PartialEq impl, hence matches!(val, pat), which is nothing more than an abbreviation of match val { pat => true, _ => false } does work. In the case of an Option, you could also use the method assert!(res.is_none()).

3 Likes

Awesome, this totally clears it up for me. Thanks a lot for the explanation!

You can provide your own error message:

assert!(res.is_none(), "{:?} != None", res);

(assuming of course that res implements Debug)

1 Like

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.