Skip to content

Cell::update #2171

@ghost

Description

I was wondering why we don't have a method like the following for Cells:

impl<T: Copy> Cell<T> {
    fn update<F: FnMut(T) -> T>(&self, f: F) {
        self.set(f(self.get()));
    }
}

This makes some particularly annoying use cases like updating counters easier (see before and after for comparison):

data.dep_kind.set(cmp::max(data.dep_kind.get(), dep_kind));
data.dep_kind.update(|k| cmp::max(k, dep_kind));

self.has_errors.set(self.has_errors.get() | old_has_errors);
self.has_errors.update(|e| e | old_has_errors);

self.count_imm.set(self.count_imm.get() + 1);
self.count_imm.update(|c| c + 1);

Why require T: Copy instead of T: Default? Because otherwise you might accidentally run into bugs like:

foo.update(|f| {
    let x = bar.set(foo.get()); // Ooops, `foo.get()` returns `0` instead of `f`!
    f + x
});

And why not T: Clone instead? Because it might introduce hidden costs.
For example, to append "..." to a Cell<String>, you might do:

let mut s = foo.take();
s.push_str("...");
foo.set(s);

But if update cloned values, that'd introduce a hidden allocation:

let mut s = foo.update(|mut s| {
    s.push_str("...");
    s
});

Here's a nicer version of the same thing. It still has an allocation, but with T: Default there wouldn't be one, so one might (incorrectly) expect this to be efficient:

foo.update(|mut s| s + "foo");

All in all, T: Default and T: Clone have subtle pitfalls, but Cell::update with T: Copy seems like a safe choice and would be a nice addition to the standard library. After all, T: Copy is by far the most common use of Cell anyway, which can be confirmed by a quick ripgrep through the rustc codebase.

Metadata

Metadata

Assignees

No one assigned

    Labels

    T-libs-apiRelevant to the library API team, which will review and decide on the RFC.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions