Skip to content

Expose Arc::is_unique #560

Closed
Closed
@SabrinaJewson

Description

@SabrinaJewson

Proposal

Problem statement

There is currently no way to check whether an Arc has unique access to its data that doesn’t involve producing an &mut to the inner data. However, this is undesirable for some use cases as it invalidates existing pointers to the Arc.

Motivating examples or use cases

Suppose one has a self-referential data structure consisting of an Arc<T> and an &T, though the &T may also for instance point to static data and not the Arc, and the goal is to write a function that produces a T from this data structure. One implementation would be to first check whether if the Arc is unique and then check if the &T indeed points to the Arc, and if so, call Arc::into_inner, otherwise clone the T from the reference. However, currently the step of checking if the Arc is unique will force the &T to be invalidated, meaning one cannot later clone should the second check fail.

In a simple case one could just reorder the two checks to solve this issue, but this is not always trivial to achieve depending on what abstractions are involved: for example, if there were multiple possible backing Arcs, one would have to check all of the pointers before attempting to Arc::into_inner the first, instead of being able to short-circuit should the first succeed. In a more complex case, if the dependent data was not &T but had a destructor, there would be no way to correctly run it: if the destructor was run before get_mut or into_inner, it would be impossible to recover the original data to clone it later, but if it was run after, it would already be invalidated.

Solution sketch

impl<T, A> Arc<T, A> {
    pub fn is_unique(&self) -> bool;
}

One argument for the inclusion of this API directly is that, even when lifetime-extended references are not involved, some people might try and, instead of calling Arc::get_mut(&mut arc).is_some(), call Arc::strong_count(&arc) == 1 – indeed, grep.app displays many results for this pattern – and not be aware of the race condition this may introduce should weak references exist, leading to code that is subtly wrong. Introducing this method makes it more likely that people will choose the correct way of implementing this function.

Alternatives

impl<T, A> Arc<T, A> {
    pub fn as_mut_ptr(&mut self) -> Option<*mut T>;
}

This doesn’t come with the discoverability advantages of is_unique mentioned above. However, it does make it more explicit that one can obtain mutable access to the internal value, which might be convenient. It is currently not guaranteed that one can mutate through the pointer returned by Arc::as_ptrthere was one attempt to guarantee this that fizzled out – but it is unlikely that we will not end up guaranteeing this.

Another alternative is having the method take &mut self instead of &self. This can reduce footguns since is_unique is rarely useful when used as an &self method, but it is possibly outweighed by the flexibility.

Links and related work

None I’m aware of.

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions