Box Borrow Implementation

Hi all,

I've been learning on rust smart pointers and collections, and there is a question stucked in my mind. Why Rust' Box, Rc, Arc don't implement Borrow for its internal type like this:

impl<T, Q: ?Sized> Borrow<Q> for Box<T> 
where 
    T: Borrow<Q>
{
    ...
}

For context, I'm working with HashMap<Rc<String>,i32>. And I want to do something like this:

let m: HashMap<Rc<String>,i32> = ...;
let k: &str = "some_sring";
m.get(k); // this fails

It seems the m.get(k) is failing because Rc<String> doesn't implement Brrow<str>, and it only implements Borrow<&String>. So I need to convert my &str to String in order to use it. I'm ok with this limitation. But, I want to know why does this is the case, and I want to know if I'm missing something.

This isn't what you're asking, but why not use Rc<str> instead of Rc<String>? This has less indirection and solves the borrow problem.

3 Likes

They would conflict with

impl<T: ?Sized> Borrow<T> for T {}

And also Box is #[fundamental], which means you can implement traits for Box<LocalType> like you can for LocalType, so adding it for Box specifically would be a breaking change.

I think the conflict is legit without considering #[fundamental] anyway though... yep, it is.

2 Likes

Interesting, I didn't know we can use Rc like this. This seems better, thank you.

Yeah, I noticed this, and it makes sense.
But, I spend quite some time thinking why we ca't do something like this:impl Borrow<Q> for Box<T> where T != Q, T: Borrow<Q> and make it non-conflicting with impl Borrow<T> for Box<T>.

Negative reasoning with regards to coherence is so far intentionally limited in Rust, as it makes things much more fragile in the general case: suddenly implementing a new trait for a concrete type is a breaking change. But there is an interest in expanding coherence. Progress seems slow however.

Here's an open RFC for != specifically, with the difficulty of assigning meaning to != mentioned in passing here.

It still would be breaking for Box due to the #[fundamental] thing though.


If you want to read way more about negative reasoning and coherence more generally, there's

1 Like

Though really, the problem is only with blanket implementations. Various covered implementations for combinations of std types could be added, which I guess is what this issue is about.

Many combinations of the existing std Borrow implementations would be variations on the impl Borrow<UnsizedThing> for Box<SizedThing> though, to which the answer is probably "just use Box<UnsizedThing> instead", as with your Rc<str> case.

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.