Wrapper to make any clonable structure also copyable?

Is there any one-line solution to give any externally defined structure implementing method clone trait copy?

Something like Copyable< Vec< u8 > >::new( vec1 )?

Copy performs a bitwise copy, you cannot do that for arbitrary Cloneable types. For Vec in particular it would result in a double free when both copies go out of scope (and general memory unsafety when using both copies).

6 Likes

Probably I phrased the question badly. Vector has method clone(), right? I meant the wrapper should call clone() on copying. Purpose to loosen restriction of explicit calling clone() when it is required to do so.

You cannot run custom code on copies or moves, both are always bitwise copies

7 Likes

Can't I call vec1.clone() from copy?

I don't think so. Maybe you want to avoid writing "clone()" but Rust has a philosophy ( mostly ) of not allowing what is going on to be hidden.

5 Likes

That's correct. To have monomorphic code.
Monomorphic code is also a principle Rust aims.

No, you can't customize the behavior of copying at all. This is deliberate on the part of the language designers and will never change.

8 Likes

I see.

Copying in Rust is strongly related to moving. Moving is not customizable in Rust either. Moving an object in Rust always does a bitwise copy (shallow copy, not a deep copy, if the struct / enum contains pointer-types), and then the moved-out-of object is invalidated / forgotten / becomes inaccessible. This is mostly a static check (at compile-time) – the compiler will know not to call any destructors anymore and allows using a variable after you moved out of it, etc…

Then, copying in Rust is basically the same as moving, but without the invalidation part. You can still use a variable after you’ve copied it.

7 Likes

Makes sense.

Good article : Moves, copies and clones in Rust

2 Likes

“mostly”, because in complicated situations, the compiler may actually introduce flags under the hood, that are used at runtime to determine whether or not destructors still have to be run on certain variables.

This also means you’ll never have to worry about overhead from copying, compared to moving. If you copy a variable and never use it anymore afterwards, then you’ve basically just moved it. It doesn’t make any difference. (If a variable can be copied, it doesn’t have a destructor either, so you don’t have to wonder whether or not a destructor still needs to run (and introduces overhead) on the copied variable).

5 Likes

Copy implies Clone. You can have uniform code if you only assume Clone.

5 Likes

  pub trait Int : Integer + Clone {}
  impl< T : Integer + Clone > Int for T
  {
  }

  pub fn is< _Int : Int >( src : _Int ) -> bool
  {
    let _0 = _Int::zero();
    let _1 = _Int::one();
    let _2 = _1.clone() + _1.clone();
    let mut i : _Int = _2;
    while i < src
    {
      if src.clone() % i.clone() == _0
      {
        return false;
      }
      i = i + _1.clone();
    }
    return true
  }

I have feeling it's sub-optimal.

You can pass references to all these arithmetic operations instead of cloning things every time.

In this case implementation will be sub-optimal for u16/u32/u64. Won't it?

I don't think so. The compiler should be able to figure out that taking a reference to a local variable and then immediately dereferencing it is a no-op.

2 Likes

The compiler should also be able to figure out that .clone() on an int doesn't need any special behavior and remove it.

1 Like

It's probably worth mentioning, since no one has, that you can't implement Copy for anything that also implements Drop, i.e. anything that has other resources attached.

7 Likes