impl AsRef<Path> for OsStr
impl AsRef<Path> for str
impl AsRef<Path> for Cow<OsStr>
but not
impl AsRef<Path> for Cow<str>
Do you folks think this impl would be useful? Admittedly it's a bit edge-casey, and users can always deref the Cow (to get a str) in cases where they want to pass a Cow<str> to functions which take AsRef<Path>.
However from a symmetry argument, we already implemented for Cow<OsStr>, and arguably Cow<str> is a more common type from what I've seen, so the implementation may save users a few characters here and there.
Hmm, actually looks like it's not that simple. Adding this impl can break code, as .as_ref() on Cow<str> suddenly takes on a second meaning. It's probably not worth trying to figure this out!
I have a feeling that this one in particular is pretty common though, since getting a &str from a Cow<str> is a common operation (obviously), and this is one of the easier/more common ways to do it.
That's just to say, it might be worth doing a crater run as a smoke test.
Yeah, I mean this really seems like it'll break a lot. If I clone the Rust repository, add this impl to the stdlib, and then try ./x.py test --stage 1
error[E0282]: type annotations needed
--> /home/david/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.4.6/src/re_unicode.rs:1247:14
|
1247 | self.as_ref().replace_append(caps, dst)
| -----^^^^^^--
| | |
| | cannot infer type for type parameter `T` declared on the trait `AsRef`
| this method call resolves to `&T`
|
= note: type must be known at this point
error[E0282]: type annotations needed
--> /home/david/.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.4.6/src/re_unicode.rs:1257:14
|
1257 | self.as_ref().replace_append(caps, dst)
| -----^^^^^^--
| | |
| | cannot infer type for type parameter `T` declared on the trait `AsRef`
| this method call resolves to `&T`
|
= note: type must be known at this point
... I'm only a very occasional contributor to the compiler, so I don't even know how to continue with the compiler testing framework without patching the regex crate
Agreed that inherent as_ref would be the way to go. Though I didn't notice prior art of an inherent as_ref anywhere else in the stdlib when I looked briefly earlier. I would argue that special-casing the compiler is undesirable - the array .into_iter() special case was much more worth the effort than this nice-to-have.
Not sure I'm invested enough in having this impl at this point! I'm going to leave this unimplemented for now, though I guess anyone who wants this impl in the future always has this thread as a good starting block.
I think that an inherent as_ref here would be a weird hack. Especially since the use-cases of as_ref for &Cow<'_, T> -> &T are covered by the Deref implementation of Cow. The two occurrences in re_unicode probably will work with the .as_ref() calls simply removed entirely (using the Deref for the method call then).
I think that aiming for a more general solution would be worth the effort of implementing such a special-casing mechanism. Ideally, if we could somehow make certain trait implementations take precedence over others for type inference (?) or method resolution (?) or whatever the most relevant mechanism at play here is, that’s a neat feature to improve the current situation of “allowed breakage” from adding trait impls in the standard library. Even for things less common than Cow<str>, we could avoid any potential for breakage entirely by somehow marking such new trait implementation as “newer” and hence “less important” an letting the compiler pretend it isn’t there in some contexts (i.e. in type inference or method resolution or where ever necessary). Similar to .into_iter(), we’d always eventually remove those special precedence rules over then next edition.
As far as I understand, the intention of the suggestion of an inherent method “as_ref” (particularly on Cow<str> taking &self, returning &str) was to avoid breakage in existing code. A different name isn’t an option, if that’s the goal. Notably, the inherent method was not meant for the conversion to &Path. The AsRef trait is commonly used as a trait bound on functions to make them less picky w.r.t. their argument type. An fn foo(x: impl AsRef<Path>) can take a &PathBuf or &str or String or an OsString or a &&&Cow<'_, OsStr>, etc. The change suggested here would allow such a method foo to not only accept Cow<OsStr> and Cow<Path> but also Cow<str>. One example of an existing such method is File::open.