# Pre-RFC: Assign \`Copy\` types to \`Cell\` without \`set()\`

**URL:** <https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081>\
**Category:** Uncategorized\
**Created:** [February 4, 2022, 3:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081 "2022-02-04T15:07:54Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![camsteffen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/camsteffen/32/3246_2.png) [@camsteffen](https://internals.rust-lang.org/u/camsteffen)\
**Post date:** [February 4, 2022, 3:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/1 "2022-02-04T15:07:54Z")

</div>

TL;DR allow `fn f(x: &Cell<u32>) { *x = 1 }`

I just did a large refactoring with `Cell`, changing assignments to use `get()` and `set()` instead. Being forced to use `get()` and `set()` when the types are `Copy` feels like meaningless churn, and perhaps an unnecessary deterrent from using `Cell`. `Cell` should just stay out of my way unless I try to do something wrong.

Could we add support for using the assignment operator for `Cell<T> where T: Copy`? Or perhaps allow coercion between `Cell<T>` and `T`, which would also allow assignment in both directions?

---

<div class="post-metadata">

**Author:** ![kpreid](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kpreid/32/8484_2.png) [@kpreid](https://internals.rust-lang.org/u/kpreid)\
**Post date:** [February 4, 2022, 3:31pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/2 "2022-02-04T15:31:12Z")

</div>

The current semantics of unary `*` are such that every mutating usage of it implies the ability to get a `&mut` reference to the same place (via `DerefMut::deref_mut`) — but getting `&mut T` from `&Cell<T>` is unsound.

What extension do you propose to the language `*` such that the library `Cell` can treat it like `set()` instead?

---

<div class="post-metadata">

**Author:** ![camsteffen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/camsteffen/32/3246_2.png) [@camsteffen](https://internals.rust-lang.org/u/camsteffen)\
**Post date:** [February 4, 2022, 4:12pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/3 "2022-02-04T16:12:14Z")

</div>

In my initial example the `*` only derefs `&Cell` to `Cell`. I'm not proposing that derefing a `Cell` should be allowed.

As for the actual language extension, the user-level explanation is that assignment of `T` to `Cell<T>` "just works". Implementation-wise, there would have to be a special case in typeck to coerce the left hand side from `Cell<T>` to `&mut T`. Once typeck passes, we're out of the woods because `Cell` is `repr(transparent)`.

---

<div class="post-metadata">

**Author:** ![jdahlstrom](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/jdahlstrom/32/3351_2.png) [@jdahlstrom](https://internals.rust-lang.org/u/jdahlstrom)\
**Post date:** [February 4, 2022, 4:16pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/4 "2022-02-04T16:16:43Z")

</div>

Like `IndexMut` has proved to be arguably insufficient and should be supplemented by `IndexSet`, perhaps the same should be done for `DerefMut`. After all, indexing and dereferencing are very much analogous.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 4, 2022, 5:08pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/5 "2022-02-04T17:08:24Z")

</div>

So as I understand it, the proposal is to make

(shared place at type `Cell<T>`) = (value at type `T`)

"just work" when `T: Copy` (i.e. you could use `.set`).

While this is a coherent feature to make working with `Cell` less cumbersome, I think I'm -0 on it as a feature, because it's making `Cell` more special for nonspecific gain.

However, if combined with the theoretical language support for "`Cell` projection" (that is, `thing.field` works on `Cell<Thing> (place)` and gives `Cell<Field> (place)`), then I'm +¾ on cell assignment on top of that.

---

<div class="post-metadata">

**Author:** ![camsteffen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/camsteffen/32/3246_2.png) [@camsteffen](https://internals.rust-lang.org/u/camsteffen)\
**Post date:** [February 4, 2022, 6:27pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/6 "2022-02-04T18:27:38Z")

</div>

The projection idea is interesting. We can also add operators like `+=`. Though this may be possible by just adding impls.

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 4, 2022, 9:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/7 "2022-02-04T21:21:09Z")

</div>

> [@camsteffen](#):
>
> coerce the left hand side from `Cell<T>` to `&mut T`

This is unsound. The problem is that assigning to an `&mut T` first drops the old `T` and then writes the new one. This is problematic because `T` receives an `&mut T` in its drop implementation, but while that exists it could access the `Cell<T>` you're writing to, thus creating aliasing references. For comparison, `Cell::set` solves this by first replacing the `T` inside and then dropping it.

I'm also not that enthusiastic about special casing yet another stdlib type. I would prefer something any user can implement for its own `Cell`-like type.

---

<div class="post-metadata">

**Author:** ![toc](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/toc/32/6692_2.png) [@toc](https://internals.rust-lang.org/u/toc)\
**Post date:** [February 5, 2022, 3:54am UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/8 "2022-02-05T03:54:18Z")

</div>

> [@SkiFire13](#):
>
> assigning to an `&mut T` first drops the old `T` and then writes the new one

I don't think these semantics are quite fully fleshed out; is this a requirement for `Copy` types?

---

<div class="post-metadata">

**Author:** ![SkiFire13](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/skifire13/32/7579_2.png) [@SkiFire13](https://internals.rust-lang.org/u/SkiFire13)\
**Post date:** [February 5, 2022, 1:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/9 "2022-02-05T13:15:42Z")

</div>

Oh right, I forgot for a moment this is restricted to `Copy` types. `Copy` requires `!Drop` so it should be fine.

---

<div class="post-metadata">

**Author:** ![H2CO3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/h2co3/32/2849_2.png) [@H2CO3](https://internals.rust-lang.org/u/H2CO3)\
**Post date:** [February 5, 2022, 4:21pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/10 "2022-02-05T16:21:31Z")

</div>

> [@SkiFire13](#):
>
> I'm also not that enthusiastic about special casing yet another stdlib type.

This. I'm not at all convinced "makes refactoring somewhat shorter-looking" is a valid argument at all for a new language feature and the special-casing of a library type.

---

<div class="post-metadata">

**Author:** ![camsteffen](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/camsteffen/32/3246_2.png) [@camsteffen](https://internals.rust-lang.org/u/camsteffen)\
**Post date:** [February 5, 2022, 5:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/11 "2022-02-05T17:34:38Z")

</div>

I get that special casing a library type isn't something to take lightly. But `Cell` isn't "just" a library type in the same way as `Option` or `Vec`. It is more similar to `core::marker::*` traits which enable a primitive language feature for a type. `Cell` enables interior mutability. So I think it is good for it to behave like a marker rather than a container in cases where that behavior can be provided coherently.

---

<div class="post-metadata">

**Author:** ![CAD97](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cad97/32/3460_2.png) [@CAD97](https://internals.rust-lang.org/u/CAD97)\
**Post date:** [February 5, 2022, 7:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/12 "2022-02-05T19:09:55Z")

</div>

> [@camsteffen](#):
>
> enable a primitive language feature for a type. `Cell` enables interior mutability.

Actually, the language item is [`UnsafeCell`](https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html). `Cell` and `Mutex` are then built on top of `UnsafeCell` with no special language semantics at all.

---

<div class="post-metadata">

**Author:** ![dhm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/dhm/32/4879_2.png) [@dhm](https://internals.rust-lang.org/u/dhm)\
**Post date:** [February 5, 2022, 10:07pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/13 "2022-02-05T22:07:41Z")

</div>

I don't really see why the `Copy` bound is relevant, here? It would, however, be, for the symmetrical operation: that of making `let value = *x;` Just Work™ as well.

I wonder if this couldn't start prototyped as a proc-macro first, transforming all the `<place> = <value>;`s into `<place>.set(<value>)`, with an added extension trait or something to handle the `&mut` case as well 🤔

- [Basic PoC, only handling top-level statements](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=041f18e4e5367be45f4286dfaf53bdd1)

---

<div class="post-metadata">

**Author:** ![tvallotton](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tvallotton/32/8153_2.png) [@tvallotton](https://internals.rust-lang.org/u/tvallotton)\
**Post date:** [February 11, 2022, 8:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/14 "2022-02-11T20:10:32Z")

</div>

In fact, if you had such a trait you may not even need `IndexSet`. Suppose you hand this trait:

```rust
// Sugar for:
// *prt = value;
trait DerefSet<Inner> {
    fn deref_set(&mut self, val: Inner);
}

```

Then a map could return a reference to a smart pointer that implements Deref, DerefMut and DerefSet.Then you would be able to write something like this:

```rust
*map[key] =value;
// As sugar for this
(*map.index_mut(key)).deref_set(value)
// here index_mut returns something like `&mut OptionRefMut<V>`

```

Now it would be nicer if IndexMut wasn't limited to returning a reference, and it could return any smart pointer.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 12, 2022, 8:11pm UTC](https://internals.rust-lang.org/t/pre-rfc-assign-copy-types-to-cell-without-set/16081/15 "2022-05-12T20:11:22Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
