I was looking for a function to get the T from inside an Arc<T> (where T: Sized) and could find one. It would be implemented equivalent to
impl<T: Clone> Arc<T> {
/// Gets the inner value out of this `Arc` if there is at most `1` strong reference, otherwise
/// clones the inner value.
pub fn into_inner(this: Self) -> T {
Arc::try_unwrap(this).unwrap_or_else(|arc| (*arc).clone())
}
}
Just like to bikeshed the name a bit: into_inner implies that it always takes ownership of the inner value. I'd prefer it to be called something like unwrap_or_clone.
How about make_unique? This has symmetry with make_mut. I prefer it over make_owned because we already own the data in the Arc, it's just that we share the ownership. I feel like unwrap_or_clone is a more direct description of what the function does, but doesn't have the symmetry with make_mut.
I'm probably tending towards unwrap_or_clone (which matches the heart contest) because it says what it does. I'll open a PR with that name, then we can bikeshed more there if needs be.
I don't know, but I think for this to be justified you need to show this is a common need, and not something that would only be used very rarely. What exactly was the use case? I have used Arc::make_mut, but I don't remember wanting this variation.
The make_mut changes the receiver (the Arc) in place and makes it unique too. Because of that I don't think the make_* pattern applies here. It seems a bit like .into_owned() or .to_owned() with preference to the former.
Cow is slightly different in that it calls to_owned rather than clone. That’d be a reason not to use the exact name into_owned. (Alternately, maybe that’s a more useful operation anyway? It supports strictly more types.)
Well, I don't think that matters (especially because of the blanket impl ToOwned for T where T: Cloned), but Cow is completely and drastically different from Arc for another reason.
Cow is designed to be single-owner. When you use a Cow, you essentially say "I don't need ownership but I don't mind if I happen to have it". By using Arc, you state that "I need shared ownership". The Cow::into_owned method optimizes for the case where you already have ownership, accounting for the possibility that you didn't, so far. In contrast, with Arc, you unconditionally have (shared) ownership, and the optimization is about uniqueness. So calling it into_owned() doesn't make much sense, because the wrapped value is already owned. make_owned() is subpar for the same reason.
I think take() is completely out of question. It is used for unconditionally stealing a value out of a place (vis. mem::take() and Option::take()), without the hidden possibility of a potentially expensive clone. Furthermore, this proposed method on Arc would not invalidate the other Arcen, but it would consume the one it is being called on – this is also completely inconsistent with the other two takes() accepting a mut ref.
It does seem like it might be possible to use specialization to detect the case where <T as ToOwned>::Owned == T (the general case where try_unwrap could be used); along with a special case for Arc<[T]> -> Vec<T> which just does a realloc rather than a copy. But for types outside std, where there's no way to use specialization, if they don't match the case that Clone would satisfy, it would end up just being the equivalent of arc.to_owned().