Closed Others closed 3 years ago
Take a look at https://github.com/rust-lang/rfcs/pull/2944. It's not sufficient for my GC's use case, but it might be for yours.
@Avi-D-coder actually reading that was the impetus for me to create this issue! I think Freeze
isn't good enough for me either, since Box<RefCell<T>>
is not Freeze
. (And what I really need to capture is that there is no interior mutability outside of a Gc
.)
Box<RefCell<T>>
would be Freeze
, since !Freeze
is not transitive across pointers.
@mtak- That doesn’t seem to match RFC?
My type doesn't implement Freeze, but I need it to be Freeze. To convert a type which is not Freeze, into a Freeze type, all that is required is to stick it on the heap. For example, Box
is Freeze even if T is an UnsafeCell.
To translate those sentences to your specific type:
RefCell<T>
is not Freeze
, but Box<RefCell<T>>
is Freeze
.
EDIT: Others have noted those lines are a bit confusing. So I'll take this issue into account while rewriting it.
@mtak- my mistake, I misspoke in my original comment. The problem with Freeze for shredder is exactly that Box
Ah. So you want deep immutability. Do you mind explaining why shallow immutability isn't enough? I do not know much about how shredder
works.
@mtak- During certain parts of collection I can’t allow certain gc objects to be concurrently modified. That’s why I require guarded access.
However if data is deeply immutable (and Sync), it’s okay to have a Deref implementation. (Since I only care if the data is changed.)
Furthermore each Gc is treated separately, so shredder could also allow Deref if you use Gc to wrap your mutable data.
Honestly Freeze is just not capturing what I need. That’s why (as I mentioned in the RFC thread), I want opt-in user defined auto traits in some form. (Although I might be able to emulate this in my Scan derive.)
(Wrote this on my phone—apologies for any typos)
I think the path forward for this is to introduce another couple of traits.
We need the trait to guarantee the deref constraint--that the data is sync and lacks interior mutability.
// Allowed only when the object is deeply immutable
unsafe trait GcDeref: Sync {}
We need a smart pointer that allows deref:
struct DerefGc<T: GcDeref + Scan>
Secondly, we need a trait to represent that the data can have a safe destructor (we can't have a destructor DerefGc
s! That could lead to undefined behavior in the presence of data cycles. )
// Allowed only when we can access no `DerefGc<T>`
unsafe trait SafeToDestruct {}
I think this design is workable, but may only be possible on nightly--where we can set up auto traits. It'd be nice if our derive macro could somehow impl these traits when appropriate, but I think SafeToDestruct
in particular requires negative reasoning.
Also note that if we implement this, we are losing the ability to have moving collectors in the future.
Resolved on master
If the data inside the
Gc<T>
has no interior mutability (UnsafeCell
) (except for inside otherGc
s), then we canDeref
directly to the data inside. This is both a performance and an ergonomics win.We'd want to create another trait, with some name like
NoUnguardedInteriorMutablity
orImmutableDirectly
, and make people derive it if they wantDeref
for theirGc<T>
.