5

An easily overlooked feature of clone() is that it can shorten the lifetimes of any references hidden inside the value being cloned. This is usually useless for immutable references, which are the only kind for which Clone is implemented.

It would, however, be useful to be able to shorten the lifetimes of mutable references hidden inside a value. Is there something like a CloneMut trait?

I've managed to write one. My question is whether there is a trait in the standard library that I should use instead, i.e. am I reinventing the wheel?

The rest of this question consists of details and examples.

Playground.

Special case: the type is a mutable reference

As a warm-up, the following is good enough when the type you're cloning is a mutable reference, not wrapped in any way:

fn clone_mut<'a, 'b: 'a>(q: &'a mut &'b mut f32) -> &'a mut f32 {
    *q
}

See this question (where it is called reborrow()) for an example caller.

Special case: the reference type, though user-defined, is known

A more interesting case is a user-defined mutable-reference-like type. Here's how to write a clone_mut() function specific to a particular type:

struct Foo<'a>(&'a mut f32);

impl<'b> Foo<'b> {
    fn clone_mut<'a>(self: &'a mut Foo<'b>) -> Foo<'a> {
        Foo(self.0)
    }
}

Here's an example caller:

fn main() {
    let mut x: f32 = 3.142;
    let mut p = Foo(&mut x);
    {
        let q = p.clone_mut();
        *q.0 = 2.718;
    }
    println!("{:?}", *p.0)
}

Note that this won't compile unless q gets a shorter lifetime than p. I'd like to view that as a unit test for clone_mut().

Higher-kinded type?

When trying to write a trait that admits both the above implementations, the problem at first feels like a higher-kinded-type problem. For example, I want to write this:

trait CloneMut {
    fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a>;
}

impl CloneMut for Foo {
    fn clone_mut<'a, 'b>(self: &'a mut Self<'b>) -> Self<'a> {
        Foo(self.0)
    }
}

Of course that's not allowed in Rust (the Self<'a> and Self<'b> parts in particular). However, the problem can be worked around.

General case

The following code compiles (using the preceding definition of Foo<'a>) and is compatible with the caller:

trait CloneMut<'a> {
    type To: 'a;

    fn clone_mut(&'a mut self) -> Self::To;
}

impl<'a, 'b> CloneMut<'a> for Foo<'b> {
    type To = Foo<'a>;

    fn clone_mut(&'a mut self) -> Self::To {
        Foo(self.0)
    }
}

It's a little ugly that there is no formal relationship between Self and Self::To. For example, you could write an implementation of clone_mut() that returns 77, completely ignoring the Self type. The following two attempts show why I think the associated type is unavoidable.

Attempt 1

This compiles:

trait CloneMut<'a> {
    fn clone_mut(&'a mut self) -> Self;
}

impl<'a> CloneMut<'a> for Foo<'a> {
    fn clone_mut(&'a mut self) -> Self {
        Foo(self.0)
    }
}

However, it's not compatible with the caller, because it does not have two distinct lifetime variables.

error[E0502]: cannot borrow `*p.0` as immutable because `p` is also borrowed as mutable

The immutable borrow mentioned in the error message is the one in the println!() statement, and the mutable borrow is the call to clone_mut(). The trait constrains the two lifetimes to be the same.

Attempt 2

This uses the same trait definition as attempt 1, but a different implementation:

trait CloneMut<'a> {
    fn clone_mut(&'a mut self) -> Self;
}

impl<'a, 'b: 'a> CloneMut<'a> for Foo<'b> {
    fn clone_mut(&'a mut self) -> Self {
        Foo(self.0)
    }
}

This doesn't even compile. The return type has the longer lifetime, and can't be made from the argument, which has the shorter lifetime.

Moving the lifetime parameter onto the method declaration gives the same error:

trait CloneMut {
    fn clone_mut<'a>(&'a mut self) -> Self;
}

impl<'b> CloneMut for Foo<'b> {
    fn clone_mut<'a>(&'a mut self) -> Self {
        Foo(self.0)
    }
}

Relationship with Clone

Incidentally, notice that CloneMut<'a, To=Self> is strictly stronger than Clone:

impl<'a, T: 'a> CloneMut<'a> for T where T: Clone {
    type To = Self;

    fn clone_mut(&'a mut self) -> Self {
        self.clone()
    }
}

That's why I think "CloneMut" is a good name.

Community
  • 1
  • 1
apt1002
  • 969
  • 6
  • 15
  • 3
    `CloneMut` is simply too hard to understand. IMO, references are basically useful at only one level, and you shouldn't try to achieve something more complex by nesting them or assigning them to each other. – Tatsuyuki Ishi Mar 27 '17 at 05:14
  • 2
    I would NOT call this `CloneXXX` seeing as mutable references are not `Clone`. – Matthieu M. Mar 27 '17 at 07:16
  • 1
    @MatthieuM. `FnMut` things are not always `Fn`, but we are happy with "`FnMut`". I think you need a better reason. – apt1002 Mar 27 '17 at 22:34
  • ToOwned is another candidate. It has the associated type, and it puts a bound on it to relate it to the Self type. However, the bound is not satisfied in my case (you can't lengthen a lifetime by borrowing) so I guess that's wrong too. – apt1002 Mar 27 '17 at 22:44
  • Actually maybe that does work. If `'b: 'a` as in the question and I reborrow an `&'b mut T` as an `&'a mut T`, then can I implement `borrow_mut()` so that it turns `&'c mut &'a mut T` into `&'c mut &'b mut T`? If so, then this is the bound I want on the associated type, and my CloneMut is perhaps better called ToOwnedMut? – apt1002 Mar 27 '17 at 22:53
  • 1
    https://github.com/rust-lang/rfcs/issues/1403 seems to be related. – qbt937 Aug 13 '17 at 20:34

1 Answers1

1

The key property of &mut references is that they are unique exclusive references.

So it's not really a clone. You can't have two exclusive references. It's a reborrow, as the source will be completely unusable as long as the "clone" is in scope.

Kornel
  • 97,764
  • 37
  • 219
  • 309