In Rust std::borrow the Clone-on-Write container(Cow<'a, T>) allows us to pass the value either as owned, or as immutably borrowed. This container works transparently with Borrow.
I would like to understand why there is no "CowMut" counterpart for BorrowMut that would keep the borrowed variant as a mutable reference.
It is easy to express such type manually, but I'm not quite sure why it is not a part of the standard library? Is it some kind of an anti-pattern?
I can imaging the situations where such object will be useful. E.g. we have a function that accepts &'a mut T argument mutably, transforms this object, and returns data with 'a lifetime from transformed data (not necessary another reference). If we want this function to behave for 'static too, we would have to pass a static mutable reference to T. In most cases this is pointless when we just want to receive owned value of static lifetime from this function passing owned value of T.
I think there's just less use-cases / the use-cases are more niche. I've seen more Cow<'_, str> than any other, and &mut str is relatively limited (manipulating ASCII?), for example.
That said, I can think of some uses that take &mut MutCow[1] for the purposes of avoiding allocation as much as possible (e.g. I have a [T; N] that needs modified and maybe, but not always, grown (turned into a Vec<T>)). This is somewhat analogous to using Cow<'static, str> to avoid allocations.
Another standard use of Cow is an AsRef-like transformation that is lossy or otherwise can't always be performed, like to_string_lossy. That is, you return a Cow after taking in some other type.
For cases when you're only returning a MutCow, I see less motivation to not just change the source material in-place, since you're returning something that logically allows mutating in-place anyway. That doesn't cover situations similar to the previous point, where you don't actually have the owned variant, but a &mut [T] into a [T; N] or what-have-you. But it does mean there's less motivation for when you do have a &mut Vec<T>.
I've struggled to understand what you mean here, and couldn't think of something where this was necessary and made sense without leaking. What's the function signature you're thinking of, with and without MutCow?
I believe you are confusing the two meanings of 'static, like many people do.
You might have seen a 'static lifetime bound explained to you as it denoting an "owned" value. However, that's not the 'static lifetime parameter in reference types!
T: 'static means that instances of T are potentially valid to keep alive for the 'static lifetime (i.e., "forever"). This means that they don't contain any temporary pointers, i.e., they own their data.
In contrast, a &'static T means that you've got a pointer of which the referent really, actually lives forever. Of course this implies that T: 'static must be true per forza; however, they are not the same constraint.
A CowMut<'static, T> is perfectly possible to construct from, or turn into, an owned value. In this regard, 'static is just like any other lifetime, and in this case, there's also no difference between mutable and immutable references. CowMut wouldn't be any more powerful in achieving this than regular old Cow. The following compiles perfectly fine:
#[derive(Debug)]
enum CowMut<'a, T: ?Sized + ToOwned> {
Borrowed(&'a mut T),
Owned(T::Owned),
}
fn main() {
let s = String::from("foo"); // definitely not lives for the 'static lifetime
let cow: CowMut<'static, str> = CowMut::Owned(s);
dbg!(cow);
}
Is it correct to say that a 'staticlifetime bound on a type T requires that typeT (not values of type T) to live forever, while a lifetime argument to a reference requires that reference to live forever, which implies the pointed-to value must live forever?
So
T: 'static â type T lives forever (but not necessarily values of type T)
&'static t â value t (e.g. of type T) lives forever
I don't think it makes (grammatical) sense to say that "a type lives for" any particular lifetime. Lifetimes are concerned with describing how long a value is around at runtime. A type itself doesn't "live" at runtime at all; it's a purely compile-time construct.
This isn't true, either â the lifetime argument on a reference is merely an upper bound on the possible lifetime of the reference itself. A &'static Titself isn't required to live for the 'static lifetime. It can live for any shorter lifetime as well. In contrast, its pointed value must actually live forever.
I feel like Cow<'a, T> is existent for the lifetime 'a only. It cannot be used afterwards. Even that being a compile-time property, I feel like it kinda(?) does make sense to say the type "lives" that long (following the terminology of lifetimes).
Isn't that only because of subtyping? Edit: but yeah, true nonetheless. I guess t would be required to live forever with &'static mut t.
No. Subtyping is why you can coerce a &'long T to a &'short T.
How long a value of type &'any T lives for is completely unrelated to subtyping â it's simple soundness logic. A pointer must not outlive its referent, but it's perfectly fine for it (the pointer itself) to exist for a shorter time. If you have a value, you don't have to point to it with something for the entirety of its lifetime!
Ooops, I also saw that I mixed up t and T. In &'static T I meant a type T. So the T needs to be capitalized. Sorry for the confusion, I'll think about this again.
(So weird, I use these things all the time, yet get confused about them.)
Trying to rephrase:
T: 'static â a bound requiring that the typeT "lives forever" (or exists forever, or could be used forever, etc. i.e. it has no lifetime parameters)
&'static T â this defines a type (a reference) which points to a value of type T, where the value must live forever
But yeah, maybe it's not the best way to say it. Thanks for correcting me on my mistakes above also.
Let me show a more practical example. We have a Box<dyn Any> type. For this type we have three different downcasting functions: by ref, by mut, and owned. In a nutshell they have similar meaning, and differ just in borrowing.
Let's introduce more polymorphic interface for downcasting:
Now we can implement it for any type regardless of borrowing. E.g. for i32:
use CowMut::*;
impl<'a> Downcast<'a> for &'a i32 {
fn downcast(from: CowMut<'a, Box<dyn Any>>) -> Self {
match from {
Owned(from) => unimplemented!(),
Borrowed(from) => Box::downcast_ref::<i32>(from).unwrap(),
}
}
}
impl<'a> Downcast<'a> for &'a mut i32 {
fn downcast(from: CowMut<'a, Box<dyn Any>>) -> Self {
match from {
Owned(from) => unimplemented!(),
Borrowed(from) => Box::downcast_mut::<i32>(from).unwrap(),
}
}
}
impl Downcast<'static> for i32 {
fn downcast(from: CowMut<'static, Box<dyn Any>>) -> Self {
match from {
Owned(from) => Box::downcast::<i32>(from).unwrap(),
Borrowed(from) => unimplemented!(),
}
}
}
We cannot do the same thing with just Cow, because there is no mutable borrow variant. We of course may use Cow::to_mut instead but for mutable borrowing it would require turning borrowed data to owned in case of mutable downcasting. And what's important more is that with just &mut Cow we will not be able to pass owned data in general.
To further rationale the CowMut we may consider Cow itself.
What is Cow? In some way this is a sort of an object that plays a role of a data container and the RAII guard for itself. We can directly borrow it's inner data either by ref or by mut reference. Cow::deref would return an immutable borrowed into it's inner value, and Cow::to_mut would turn Cow into "RAII" guard for itself for mutably borrowing it's inner data. In either case we don't have intermediate explicit RAII object for borrowing.
In this sense Cow has established design pattern from standard library that combines the container and RAII guard, but we can easily imaging of spreading of this design pattern to custom RefCells and Mutexes, such as borrowing inner data would simply be a function with mutable receiver, that would turn the container into RAII guard and return inner borrowed data directly.
Returning to my Downcast example above. With such interface we need some kind of a CowMut interface that let us pass such Container+RAII object either borrowed, or owned. And we need a way to pass it as mutably borrowed, not immutably as in Cow, because the container assumed to change it's own variant in place.
'static is not a type, and there is no subtyping between a type and a lifetime in Rust. (The only kind of subtyping is between types of the form T<'a> and T<'b> depending only on their variance and the lengths of the involved lifetimes.)
T: 'static is not a subtyping relationship. It is called a lifetime bound, and it means exactly what I wrote above.
T: 'a means that all lifetime parameters of T outlive 'a. [âĻ]
And I agree with @H2CO3 that 'static is not a type.
Not sure if that was referring to the first past of your post or a general statement. Generally, Rust uses subtyping, but only in regard to lifetime differences. For example, &'static str is a subtype of &'a str (for any lifetime 'a).
Subtyping is implicit and can occur at any stage in type checking or inference. Subtyping is restricted to two cases: variance with respect to lifetimes and between types with higher ranked lifetimes. [âĻ]
Rust has some fancy names of top-level constructions. Perhaps, to improve the intuition behind the language design, but in a nutshell Lifetimes and e.g. Structs have no deep difference in a sense of subtype calculus. It is fair to call them the way they named in docs, but it does not contradict the fact that they all behave as just types in a nutshell.
Well, from the type system point of view traits also can be seen as just types. That's why both traits and lifetimes can appear on the right hand side of A: B. Structs or enums cannot appear on the right hand side, but this is (again, from the type system point of view) because in Rust there is no inheritance for enums and structs. Structs and enums are the final subtypes of any other type, so having them on the right hand side is pointless. But if they could have subtypes, we would see them on the right hand side too.