+1. I have been thinking for a while that freezability and constability
will have to be separate anyhow. Oh well. It was nice while it lasted.
On the topic of implementation strategies for internal types like Cell/ARC:
At some point I was talking to brson about implementation strategies for
things like Cells and Arcs. I was thinking that should allow you to
label fields as `unsafe`, `unsafe mut`, and possibly also allow a
volatile tag. In all cases, accesses to the field would require unsafe
code. The unsafe flag serves as a warning that you will be mutating the
field via transmuted pointers or other things. The mut declaration
indicates whether the type should "appear as mutable" to the type
system. In particular, ARCs have fields that are mutated when the ARC
is copied or cloned, but the type itself should nonetheless appear
immutable. Cells on the other hand have should not appear immutable. In
both cases, to prevent incorrect LLVM optimization we need a way to
indicate that this field may in fact be mutated in funny ways. This
would ensure we don't supply LLVM incorrect alias/type information in
the future. Similarly, it may or may not be worth adding some notion of
volatile to warn LLVM that it must re-read from the value each time it
is accessed; or perhaps we should just require that any value (like the
ARC's ref count) which you suspect may be accessed across threads is
only accessed by some intrinsics (we should probably just add an
AtomicInteger type that enforces this, I guess).
Niko
Patrick Walton wrote:
Hi everyone,
Based on some discussions today, I'd like to float the idea of merging
the Cell and Mut types into a single type called Cell. The reasoning
here is basically that the two types are very similar in
functionality, and the distinction between "lowercase-m mut" and
"capital-M Mut" seems likely to be confusing to me.
The resulting type, Cell<T>, would have one byte of overhead over the
enclosed type T (to support the empty/full/borrowed flags) and would
support the following five basic operations:
(1) `insert(&self, T)`: inserts a value of the appropriate type into
an empty cell, failing if the cell is full;
(2) `remove(&self) -> T`: removes a value from a full cell, failing if
the cell is empty;
(3) `with_imm_ref<R>(&self, &fn(&T) -> R) -> R`: yields an immutable
reference to the interior of the cell, failing if the cell is empty or
is borrowed mutably;
(4) `with_mut_ref<R>(&self, &fn(&mut T) -> R) -> R`: yields a mutable
reference to the interior of the cell, failing if the cell is empty or
is borrowed immutably;
(5) `status(&self) -> CellStatus`: returns the status of the cell,
which is one of `Empty`, `Full`, `BorrowedImm`, or `BorrowedMut`.
Under the hood, this would be implemented with unsafe code.
The use cases here are:
1. As a friendlier replacement for mutable fields where you really
want only a few fields of a structure to be mutable, and you don't
want to have to use garbage collected `@mut` pointers.
2. Moving values out of closures that are not one-shot. I don't know
how often this will occur in practice, but it seems prudent to have a
story for the times when you actually need to do this.
What I *don't* like about this scheme is that it means that the notion
of a freezable data type is distinct once more from the notion of an
owned data type. Not only does this result in added type system
complexity, but it also means that Cells pollute data structures,
making them non-ARCable. On the other hand, having the ability to make
what essentially amounts to mutable fields without the borrowing
problems that plagued mutable fields before is undeniably convenient.
So I'm somewhat torn on this, and I'd be interested to hear what
others think.
Patrick
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev