The Mutable counterpart of Cow container

Citation needed.

First off, 'static is not a type. It's a lifetime. It is because it is a lifetime that it is not a type, since lifetimes and types are different things. They are not the same. They are distinct. It's simple as that.

As for subtyping: there's no subtyping between types. Rust applies subtyping between lifetimes. But then again, lifetimes are not types. So there is subtyping between lifetimes, and there is no subtyping between types.

No, traits are very much not types, either. You can have values and variables of any given type. But you can't have variables of lifetime or trait "type". (Yes, I know about trait objects – a trait object and a trait aren't the same, either.) This is precisely the reason for why lifetimes and traits are not types.

You are deeply confused about the : bound syntax and you think of Rust like an OO language. That is an honest mistake from someone coming from an OO language.

Unfortunately, it does not help if you try to re-define terms long established in the ecosystem for your personal taste. You'll meet great resistance convincing experienced Rust programmers that they for some reason should be using object-oriented terminology. If you are genuinely trying to learn, then please accept the existing definitions. If you are trying to convience us of your particular unorthodox views on type theory, then please stop.

Type theory has nothing to do with OO languages, nor my personal background in programming.


Unfortunately, however, the above argument doesn't have much to do with "type theory". It has to do with what things in Rust are called concretely, and how they work. You can use big words, but that doesn't change the fact that your assertions are not true in the context of Rust.

Indeed, I actually meant that T: 'a does not express a subtying relationship. Fixed and elaborated.

OK, your example is pretty much what I thought you meant.

It doesn't really work as illustrated by the unimplemented!() parts: there's no way to return a &'a or &'a mut without leaking or (in the non-mut case) returning some dummy static value when the method receives the owned variant. The same is true with Cow.

    fn downcast(from: CowMut<'a, Box<dyn Any>>) -> &'a i32 {
        match from {
            // Can't borrow for `'a` here as the value drops
            // at the end of this function
            Owned(from) => unimplemented!(),
            Borrowed(from) => from.downcast_ref().unwrap(),

Taking by reference doesn't help.

    // new             v
    fn downcast2(from: &CowMut<'a, Box<dyn Any>>) -> &'a i32 {
        match from {
            // Can't borrow for `'a` here as we can't be sure
            // the value doesn't drop before that; we can only
            // return a lifetime as long as the anonymous
            // outer lifetime. 
            Owned(from) => unimplemented!(),
            // Moreover, since you're using `&'a mut`, you
            // can't get a copy of the inner reference out
            // behind the outer refernce like you can with
            // `Cow`, so this will fail too (it is also
            // capped to the outer lifetime).
            Borrowed(from) => from.downcast_ref().unwrap(),


For the owning case, there's no reason to require 'static. The owning variant, though unimplemented in your example, could work in your example by downcasting first and then copying (or cloning) out the i32.

More generally though, if std had CowMut, it would probably have the same semantic constraints as Cow -- including the Borrow/ToOwned constraints. There is no to_owned for Box<dyn Any>, so Cow<'_, Box<dyn Any>> doesn't compile. The same would likely be true of CowMut, if std gained one.

That is, whatever abstracting-over-borrowed-or-owned construct you may want, it's probably not Cow-esque.

1 Like

Well, I think the mistake in my intuition was that I misinterpret Cow as a container for borrowed-or-owned abstraction. While it has such property, it was not design for this specific purpose in first place.

1 Like

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.