I just found that (again...) the types in the vec module were changed
and they are now unsound with respect to mutability. I just wanted to
send a brief e-mail to try and explain why things are the way they are.
In general, we are too loose with respect to mutability when it comes to
unsafe pointers, and we make excessive use of reinterpret_cast, so the
compiler can't help us catch mistakes. We then end up with "safe"
external interfaces that are in fact unsafe. Prime among them,
`vec::each`, which is currently written:
fn each(v: &[const T], f: fn(&&v: T) -> bool) { ... }
The reason that this is unsafe is because the callback `f` expects an
*immutable reference* to `T`. This means, in practice, it expects a
pointer to `T` that it can rely upon not to be overwritten. But the
vector we are iterating over, `v`, is not guaranteed to have *immutable*
contents, only *const* contents (that is, contents which may or may not
be immutable).
The reason that this function compiles at all is because `as_buf()` has
incorrect types:
fn as_buf(v: &[const T], f: fn(*T, uint));
Here you see that `as_buf` takes a vector with `const` contents and
produces a pointer `*T` that is supposedly pointing at *immutable*
memory. But of course it's not, not really, it's pointing at const
memory. The correct type of as_buf is:
fn as_buf(v: &[T], f: fn(*T, uint));
To accomodate `&[const T]` or `&[mut T]`, there are other functions:
fn as_const_buf(v: &[const T], f: fn(*const T, uint));
fn as_mut_buf(v: &[mut T], f: fn(*mut T, uint));
All of these functions exist (I put them in a while back), but
`as_buf()` is over-used because it is incorrectly typed.
In practice, what these various rules mean is that basically what winds
up happening is that almost all `vec` functions only work on `&[T]`.
This is generally ok for two reasons. First, I would say that the type
`~[mut T]` is almost always not what you want. Due to inherited
mutability, you probably want to replace code like this:
let x = ~[mut 1, 2, 3];
x[0] += 1;
with
let mut x = ~[1, 2, 3];
x[0] += 1;
In fact, your variable was probably `mut` to begin with, since you
probably had to grow up your array.
But, even if you continue to use `~[mut T]` for some reason, such a type
can in fact *still be coerced to &[T]*, so long as the fn using the
slice is pure. Most places in vec that today are written with `&[const
T]` basically just want an array they can read. It is better to declare
such fns as pure and require a `&[T]`.
In fact, I think we should probably just remove the notion of a `~[mut
T]` array type. Mutability qualifiers should only appear on variable
names, field names, and after an `&` or `*` sigil. But that's for
another e-mail.
Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev