5
votes

I have a few Copy types, and I really appreciate the handiness of them being Copy.

I would like one of those types to contain a mutable field, using Interior Mutability as in cell::Cell. There are probably other solutions for the problem I am trying to solve, but Interior Mutability is cheap. I like cheap.

However, it turns out that cell::Cell is not Copy, and from the comments is unlikely to become Copy as the maintainers fear this would be error-prone.

A comment by the OP is my current beacon of hope:

It's not the absolute end of the world if it doesn't for my own data structures (since I can just make my own version of Cell)

Though I do not see how they purport to achieve this feat.

The core issue I have is that UnsafeCell:

  • is mandatory to implement Interior Mutability,
  • is not Copy.

Which seems to close the door to any hope of implementing a CopyCell, unless I am missing a trick (a way to unsafe impl the Copy trait?).


MCVE:

#[derive(Clone, Copy)]
struct HelloWorld(Cell<u32>);
  |
3 | #[derive(Clone, Copy)]
  |                 ^^^^
4 | struct HelloWorld(Cell<u32>);
  |                   ---------- this field does not implement `Copy`

What should I replace Cell with for HelloWorld to be Copy?


Note: at the moment, the only way I can see of achieving the desired outcome is to use a &Cell<T>; with all the lifetimes implications.

1
so, just to be sure what you're asking, you want to be able to copy Cell, but not the value inside it, right ? - Tigran
@Tigran That wouldn't make any sense. Cell doesn't provide shared ownership (unlike Rc or Arc) so in order to copy a Cell, you must copy the value inside it. - Francis Gagné
@FrancisGagné: agree, but that's what I understand from the question, which, rightfully, goes against language logic. I just wanted to clarify the point. - Tigran
@Tigran: I want to Copy both. For what it's worth my usecase is for a Cell<u32> (which is why &Cell is irksome, as it triples the memory requirement). - Matthieu M.
@Tigran: I added a code excerpt to clarify my intended usage. - Matthieu M.

1 Answers

3
votes

I think there's a good reason that UnsafeCell doesn't implement Copy: it would be unsafe in the general case. Reading from an UnsafeCell is an unsafe operation, as shown by the get method's signature: it returns a raw pointer, and dereferencing a raw pointer is an unsafe operation. A copy would implicitly read the value, which could race with another thread writing to the same UnsafeCell. Cell doesn't have that race because it is !Sync (i.e. two threads can't access the same Cell).

Personally, I would just use Clone::clone instead of messing with references. Cell's clone is #[inline], so it's highly likely that the call will be optimized away in release builds.