Impl PartialEq<Option<U>> for Option<T> where T: PartialEq<U>


#1

Right now, Option has the following impl:

impl<T> PartialEq<Option<T>> for Option<T> where T: PartialEq<T>

This only allows comparing Option<T> to Option<T>. So, for instance, if you have Option<&OsStr>, you can’t compare that to Option<&str>, even though you can compare &OsStr and &str.

Would it make sense for Option to provide:

impl<T, U> PartialEq<Option<U>> for Option<T> where T: PartialEq<U>

This would allow more general comparisons of Option values, without having to expand them into much more verbose match blocks.

The downside: this would loosen a type constraint, and a program could potentially rely on that type constraint as the only means of inferring a type. Type parameter defaults might make it possible to avoid regressions from that, by saying that U defaults to T.


#2

There are couple of existing issues about this: https://github.com/rust-lang/rfcs/issues/917, https://github.com/rust-lang/rust/issues/20063. Heterogeneous impls break comparisons like opt_something == None, it was too much breakage even for late pre-1.0 times. Hopefully default type parameters will work some day, there’s a lot of library progress blocked on them.


#3

Personally I don’t feel super concerned about breaking option == None; I would consider is_none() a more idiomatic alternative & we are ‘allowed’ to break inference. I thought there were coherence issues but I guess not?

It might be nice to do a crater run and see how bad this would really be.


#4

I’d love to see the results of a crater run, but I suspect it’d hurt enough to not be worth it without some kind of type parameter defaults.


#5

I’ve hit this exact missing impl yesterday, and one caveat that came up on irc is that it breaks type inference for things like:

Some("foo".to_string()) == Some("bar".into())

I’ll note that Option is not the only type that could benefit from such a generalization. At least Box and Result could do with such a generalization too.

Interestingly, the example above only works because of the current non-generalized impl PartialEq<Option<T>>: the compiler can’t do type inference for:

"foo".to_string() == "bar".into()

which brings the interesting point that it probably should try to make both arms have the same type at the very least. And that should automatically allow the generalized impl PartialEq<Option<T>> to not break type inference in the case above.