Replace Borrow and BorrowMut traits with AsRef and AsMut


#1

With the conversion traits in https://github.com/rust-lang/rfcs/pull/529 implemented it seems to me that the Borrow and BorrowMut traits could be removed completely as they are equivalent to AsRef and AsMut.

Is there a plan to remove these or have did they fall between the cracks? The only thing I could find about them is a comment by Gankro on the RFC so I thought I should bring it up.


#2

There’s a lot that can be replaced by the convert traits, but do we have the time? It would require removing stable items too. (FromIterator has been suggested).

Maybe it’s better to remove the convert module instead (it’s not stable). (Because consistency demands we use one or the other).


#3

The PR implementing the traits mentions some traits that were depreciated as a result of the convert traits so there seem to have been some motion towards using only the conversion traits. It would be unfortunate if duplicate traits such as the ones mentioned above were left in the standard library only due to time constraints.

Maybe the traits that could be superseded should at least be marked as unstable so that a decision can be made about them (IntoCow has already been marked unstable like this).


#4

There are two key differences between the traits:

  1. The Borrow traits are intended only to go between types that will hash identically, and whose equivalence and ordering are the same. This is important because data structures like HashMap use Borrow under this assumption. (This should be better-documented.)

  2. The Borrow traits come with a blanket “reflexive” impl: impl<T: ?Sized> Borrow<T> for T. Such an impl would make sense for AsRef as well, but cannot coexist with another important blanket impl.

In general, Borrow is intended to be implemented and used in much narrower circumstances than AsRef. But it is true that if T: Borrow<U> then you should implement T: AsRef<U> as well (just not vice versa).

Hope that helps!


#5

True, I didn’t think about the equality restriction. It makes sense to have still have a distinction between Borrow and AsRef in that case though arguably BorrowMut is of little use if equality is their only real difference.


#6

But it is true that if T: Borrow<U> then you should implement T: AsRef<U> as well (just not vice versa).

Should Borrow be a sub-trait of AsRef then, @aturon? Seems to give us more flexibility in the future if it turns out there are bounds that can be relaxed from Borrow to AsRef.


#7

Bump @aturon :slight_smile: Do ya think making Borrow a sub-trait of AsRef would be worth doing before 1.0?


#8

Sorry for the late response! Unfortunately, we cannot currently add such a restriction, because:

  1. Borrow has a blanket implementation T: Borrow<T> for all T, which is really important for its use cases;
  2. AsRef has a different blanket implementation, important for its use cases;
  3. We can’t have both blanket implementations at once, due to coherence limitations.

In the future, if we get impl specialization, we can probably provide a blanket implementation of AsRef for anything implementing Borrow, which would have a similar effect (and even guarantee that the two impls do the same thing). That can happen post-1.0.