Skip to content

Rewrite rc::Rc using cell::Cell #12654

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 21, 2014
Merged

Rewrite rc::Rc using cell::Cell #12654

merged 1 commit into from
Mar 21, 2014

Conversation

edwardw
Copy link
Contributor

@edwardw edwardw commented Mar 2, 2014

Since Arc has been using Atomic, this closes 12625.

Closes #12625.

@alexcrichton
Copy link
Member

Using a RefCell adds an extra word to all Rc values, perhaps the strong and weak counts should be Cell<uint> instead?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 2, 2014

Good point. I'll try Cell then.

@thestinger
Copy link
Contributor

Can this wait until the issue is discussed? I don't think Rc should become non-Freeze, and I think the marker type is much clearer anyway.

@alexcrichton
Copy link
Member

It seems wrong to say that Rc is Freeze because whenever it's cloned through an &-pointer it's modified. If we were to inform LLVM that the pointer is entirely immutable or use this in a threaded context, seems like things could go wrong.

To me, this is the reason why markers should not be used in favor of types with safe interfaces like Cell.

@thestinger
Copy link
Contributor

No, nothing would go wrong if we told LLVM an & pointer to Rc is immutable. There's no concept of deep immutability in LLVM. The only relevant pointer is the *mut one used for the box itself, which is already correct. You can't use it in a threaded context because it won't be Share or Send.

If the meaning of Freeze is changing, then Rc/Arc are far from the only types that need to become non-Freeze. Performing I/O is technically doing writes to memory... so deep immutability really means that all the methods have to be pure.

@nikomatsakis
Copy link
Contributor

I agree we definitely want Cell<T> and not RefCell, if we make this change.

I also agree with @thestinger, we ought to discuss. Whether this is the right call seems to hinge on just what we want the definition of Freeze to be. I was going under the assumption that Rc<T> ought not to be freeze, but maybe I was mistaken. The question is whether reaching mutable data or owning mutable data is the def'n of Freeze.

I finally think this PR is not the place to have such a discussion.

@nikomatsakis
Copy link
Contributor

After some more thought I have modified my opinion and I am still in favor of using Cell. See the issue for details. (But this is not to say we shouldn't discuss a bit further.)

@edwardw
Copy link
Contributor Author

edwardw commented Mar 3, 2014

The patch has been updated to use Cell. And some tests in syntax::ast are failing precisely because Rc doesn't inherit Freeze from T any more.

@nikomatsakis
Copy link
Contributor

The patch looks good! We probably do want to tweak the def'n of Freeze from "reaches mutable" to "interior mutability". Presumably we should do that before we land this patch.

@alexcrichton
Copy link
Member

The current plan is to possibly remove the Freeze trait entirely (to be superseded by the Share trait). The main impetus for this change is that interior mutability is not done through *mut T, but rather through Cell<T>. For that reason, the counts should use Cell<uint> rather than uint directly through the *mut pointer.

I don't have much of a preference on whether this uses *mut RcBox<T> or *RcBox<T>, although I would favor *RcBox<T> because it more accurately reflects that Rc<T> is not deeply mutable. @nikomatsakis may have some clarifications to this reasoning.

Implementation-wise, it seems odd to introduce a one-off trait for these two pointer types. Sure it's not exported, but there's no other clean way to do it? I feel like something returning &RcBox<T> is the best way about this.

@nikomatsakis
Copy link
Contributor

I agree that *RcBox<uint> is correct.

As far as the trait goes, it seemed to me like an impl detail that wouldn't be reflected in the docs and just allowed us to shave off some duplicate code, which seems like a good thing. @alexcrichton you disagree?

@thestinger
Copy link
Contributor

I don't really find * to be the right choice here. The free function takes *mut, and it's quite pointless to make the distinction if we're going to ignore it.

@nikomatsakis
Copy link
Contributor

@thestinger I see. Yes, I guess you're right, if we think of *T as *const T in C (as we ought to) then *mut is indeed correct.

@nikomatsakis
Copy link
Contributor

/me not a big fan of our current treatment of *

@alexcrichton
Copy link
Member

Doesn't that seem a little odd? By that same logic, nothing should be *T, everything should be *mut T, which seems backwards?

@thestinger
Copy link
Contributor

I'm not sure what logic you're referencing. The free function takes *mut because it uses the pointer to mutate memory, and the pointer is no longer valid after the call. If that's not a case where we're going to use *mut, then there's no reason to have it. I do think the distinction is useful, just as const is useful in C, because it does catch lots of mistakes.

The const-correctness rules in C++ are that you can coerce a non-const pointer/reference to const, but you can't go back the other way. In this case, it needs to remain *mut after the call to malloc because it is going to eventually be passed to free. It can be coerced to * to pass it to a function that's not going to mutate it.

@alexcrichton
Copy link
Member

@edwardw, this patch needs a rebase, and could you also make these changes?

  • *RcBox<T> => *mut RcBox<T>
  • Change the RcBoxPtr trait to have fn inner(&'a self) -> &'a RcBox<T>;?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

How about fn inner<'a>(&'a self) -> &'a mut RcBox<T>; ? Since it is already mut, I'm thinking there's not much need to use Cell any more.

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

The latest commit demonstrates the fn inner<'a>(&'a self) -> &'a mut RcBox<T>; idea. It is more of refactoring than rewriting now. Still kind nice, but I find the patch ... a bit thin.

@alexcrichton
Copy link
Member

The point of this patch is to not use &mut RcBox<T> sadly. Having an &mut pointer is a guarantee that you are the only thread in the world looking at this pointer, but that is not true in the case of Rc (due to clones). For this reason, the correct signature is returning &'a RcBox<T> and using Cell for interior mutability.

@nikomatsakis
Copy link
Contributor

(What @alexcrichton said)

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

So Cell it is. Note that some unit tests in syntax are failing because of Rc now doesn't inherit Freeze from T. So I guess this patch shouldn't be merged yet.

@alexcrichton
Copy link
Member

I'd rather not leave this lingering, is it possible to fix the tests before the kind inference is updated?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

Sure. Maybe with an FIXME in it?

@alexcrichton
Copy link
Member

Is it really necessary to have a FIXME? Can the test be modified?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

Unfortunately, they specifically test for being frozen: ast.rs and interner.rs.

@alexcrichton
Copy link
Member

The test in ast.rs is fine to ignore, and I don't understand why the Freeze bound is on the interner. Why are the tests in interner.rs failing but compilation succeeding?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

I guess because no other place tries to instantiate Interner with something has Rc in it such as RcStr in the test.

@alexcrichton
Copy link
Member

Can you switch the tests over to just using ~str or a similar type?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 9, 2014

Certainly. I'll try to submit a new patch then.

@alexcrichton
Copy link
Member

Closing due to inactivity, but feel free to reopen with a rebase!

@edwardw
Copy link
Contributor Author

edwardw commented Mar 21, 2014

Rebased. Since Unsafe has landed, Freeze shouldn't be a concern any more. Reopen the ticket, @alexcrichton ?

@alexcrichton alexcrichton reopened this Mar 21, 2014
@edwardw
Copy link
Contributor Author

edwardw commented Mar 21, 2014

r?

}
}

#[allow(missing_doc)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add some docs? I'd like us to avoid merging patches that add undocumented features.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an internal implementation trait, I think, so I'm not sure that docs are needed since these methods aren't publicly available and their purpose is fairly clear.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough.

Side Note: I personally prefer to have everything documented even internal and pretty obvious things. I think it's good for the language and to make newcomers life easier.

Since `Arc` has been using `Atomic`, this closes 12625.

Closes rust-lang#12625.
bors added a commit that referenced this pull request Mar 21, 2014
Since `Arc` has been using `Atomic`, this closes 12625.

Closes #12625.
@bors bors merged commit db5206c into rust-lang:master Mar 21, 2014
@edwardw edwardw deleted the rc-arc branch March 21, 2014 15:18
bors pushed a commit to rust-lang-ci/rust that referenced this pull request Apr 22, 2025
…ust-lang#14367)

There were two bugs here. Let's assume `T` is a singleton type
implementing `Default` and that `f()` takes a `T`:

- `f(<T>::default())` cannot be replaced by `f(<T)` as it was (incorrect
spans – this is tricky because the type relative path uses a base span
covering only `T`, not `<T>`) (third commit)
- The argument of `f(<_>::default())` is inferred correctly, but cannot
be replaced by `<_>` or `_`, as this cannot be used to infer an instance
of a singleton type (first commit).

The second commit offers better error messages by pointing at the whole
expression.

Fix rust-lang#12654

changelog: [`default_constructed_unit_struct`]: do not suggest incorrect
fix when using a type surrounded by brackets
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rewrite Rc and Arc to use Cell and Atomic respectively
7 participants