Skip to content

Tracking issue for Cell::update #50186

@ghost

Description

This issue tracks the cell_update feature.

The feature adds Cell::update, which allows one to more easily modify the inner value.
For example, instead of c.set(c.get() + 1) now you can just do c.update(|x| x + 1):

let c = Cell::new(5);
let new = c.update(|x| x + 1);

assert_eq!(new, 6);
assert_eq!(c.get(), 6);

Activity

added
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
B-unstableBlocker: Implemented in the nightly compiler and unstable.
on Apr 24, 2018
oli-obk

oli-obk commented on Apr 24, 2018

@oli-obk
Contributor

Not a blocking issue for merging this as an unstable feature, so I'm registering my concern here:

The update function returning its new value feels very ++i-ish. Similar to += returning the result of the operation (which rust luckily does not!). I don't think we should be doing this. Options I see:

  • return () (that was the suggestion in the PR)
  • make the closure argument a &mut T, and allow the closure to return any value.
    • if users want the "return new/old value" behaviour, they can now encode it themselves via |x| {*x += 1; *y }

Maybe there are other options?

Data point: the volatile crate's update method returns () (https://github.com/embed-rs/volatile/blob/master/src/lib.rs#L134)

ghost

ghost commented on Apr 24, 2018

@ghost

@oli-obk

I like the second option (taking a &mut T in the closure). There's an interesting variation on this option - instead of requiring T: Copy we could require T: Default to support updates like this one:

let c = Cell::new(Vec::new());
c.update(|v| v.push("foo"));

Perhaps we could have two methods with different names that clearly reflect how they internally work?

fn get_update<F>(&self, f: F) where T: Copy, F: FnMut(&mut T);
fn take_update<F>(&self, f: F) where T: Default, F: FnMut(&mut T);
ghost

ghost commented on May 2, 2018

@ghost

What do you think, @SimonSapin? Would two such methods, get_update and take_update, be a more appropriate interface?

SimonSapin

SimonSapin commented on May 14, 2018

@SimonSapin
Contributor

The T: Default flavor feels kinda awkward but I don’t know how to put that in more concrete terms, sorry :/

It looks like there is a number of slightly different possible APIs for this. I don’t have a strong opinion on which is (or are) preferable.

added a commit that references this issue on Jul 23, 2018
CodeSandwich

CodeSandwich commented on Aug 6, 2018

@CodeSandwich

Taking &mut in this method would be awesome, I would love to use it.

Unfortunately it seems that it would have to be unsafe, because AFAIK there is no way in Rust to restrict usage like this:

let c = Cell::new(vec![123]);
c.update(|vec| {
    let x = &mut vec[0];            // x references 123
    c.update(|vec| vec.clear());    // x references uninitialised memory
    *x = 456;                       // BOOM! undefined behavior
})

I hope, I'm wrong.

SimonSapin

SimonSapin commented on Aug 7, 2018

@SimonSapin
Contributor

@CodeSandwich it is a fundamental restriction of Cell<T> that a reference &T or &mut T (or anything else inside of T) must not be given to the value inside the cell. It’s what makes it sound. (This is the difference with RefCell.)

We could make an API that takes a closure that takes &mut T, but that reference would not be to the inside of the cell. It would be to value that has been copied (with T: Copy) or moved (and temporarily replaced with some other value, with T: Default) onto the stack and will be copied/moved back when the closure returns. So code like your example would be arguably buggy but still sound: the inner update() would operate on a temporary value that would be overwritten at the end of the outer one.

CodeSandwich

CodeSandwich commented on Aug 13, 2018

@CodeSandwich

I think, that a modifier method might be safe if we just forbid usage of reference to Cell's self inside. Rust does not have mechanism for forbidding usage of a SPECIFIC reference, but it does have mechanism for forbidding usage of ALL references: 'static closures.

I've created a simple implementation of such method and I couldn't find any hole in it. It's a limited solution, but it's enough for many use cases including simple number and collections modifications.

SimonSapin

SimonSapin commented on Aug 13, 2018

@SimonSapin
Contributor

A 'static closure could still reach the Cell, for example by owning a Rc.

CodeSandwich

CodeSandwich commented on Aug 13, 2018

@CodeSandwich

That's absolutely right :(

86 remaining items

tgross35

tgross35 commented on Apr 2, 2025

@tgross35
Contributor

I can't update the top post because it was created by a deleted user, but the API will be:

impl<T: Copy> Cell<T> {
    pub fn update(&self, f: impl FnOnce(T) -> T);
}
added a commit that references this issue on Apr 3, 2025
added a commit that references this issue on Apr 3, 2025
added a commit that references this issue on Apr 3, 2025
added a commit that references this issue on Apr 3, 2025
tgross35

tgross35 commented on Apr 7, 2025

@tgross35
Contributor

Crosslinking, FCP for the changed API is currently ongoing at #134446 (comment)

added 2 commits that reference this issue on Apr 8, 2025
added a commit that references this issue on Apr 24, 2025
added a commit that references this issue on Apr 24, 2025
added 2 commits that reference this issue on May 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCLibs-SmallLibs issues that are considered "small" or self-containedLibs-TrackedLibs issues that are tracked on the team's project board.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.disposition-mergeThis issue / PR is in PFCP or FCP with a disposition to merge it.finished-final-comment-periodThe final comment period is finished for this PR / Issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @comex@peterjoel@Amanieu@SimonSapin@oli-obk

      Issue actions

        Tracking issue for Cell::update · Issue #50186 · rust-lang/rust