Thanks for all the responses! I knew there was something simple I could do in my specific case - in this case, `.take()` or more generically `utils::replace`. Thanks for the pointers.
That said, the general problem remains. I think it goes as follows: - There is a container accessible from some root pointer. - One burrows a mutable pointer to some entry nested in the container. - At this point, we can split all the memory reachable from the root pointer into three kinds: A. The mutable entry data we burrowed a pointer to. B. The data along the path leading from (including) the root pointer to the mutable entry. C. Other data reachable by the container. For example, if I have a `&mut T` to the `i`th entry of a `~[T]` array, then: A. Is the `&mut T` and anything reached from it. B. Is the pointer to the base of the array (the `&mut T` is that base plus `i` * the size of `T`). C. Is all the data contained in all the entries other than the `i`th, and anything reached from them. Now, there are three kinds of mutations one can do to the container - these that mutate A, B or C data. Burrowing a 2nd mutable pointer to A data is forbidden, to avoid two mutable pointers to the same data. So far, so good. Burrowing a mutable pointer to B data is forbidden, because if it mutates than the entry we have a pointer to might be disconnected from the container or compromised in another way. Burrowing a mutable pointer to C data should be allowed, as it doesn't overlap with our mutable pointer in any way. For example, one could reasonably expect to be able to burrow a mutable pointer to both `vec[0]` and `vec[1]` at the same time. However, the type system can't tell (in general) whether a specific mutable operation on the container touches only B date or also C data. It doesn't know that `vec.push()` might change the base pointer (B data) but `vec[1]` doesn't. All it can see is that there is mutable access in both case, so it plays it safe. It is hard to do better. Even in the simple vector case. Suppose I get two parameters, `i` and `j`, and I tryu to get `&mut T` for both `vec[i]` and `vec[j]`. This is OK as long as i is different from j. If they are equal, this is forbidden. But there's no way to make these kinds of decisions in the type system - this requires a run-time check. It might be able to do somewhat better by using nested lifetimes. I'm not certain this can be done in a general way using the current type system, though. But even with nested lifetimes, this wouldn't solve the general problem. When the static type system fails, one must rely on either unsafe code ("trust me") or a dynamic type system ("verify me"). The latter may be expensive - in fact, supporting "verify me" might require extra cost for code that has no need for this feature (to make relevant meta-data available and up-to-date). Right now, Rust goes along the way of "trust me". That said, there are idioms (like `take`) which can hide the nastiness in their inside. Perhaps we need a cheat cheat of common use cases and the patterns for achieving them using the current mechanisms (that is, libraries that provide support for the common use cases). ARC for example, but also `take` and `replace` and I guess a few more besides. Then we could say "if you feel none of them is enough, define a new useful generic safe mechanism (with unsafe internals) to cover the case"; but in general all containers code should not include any `unsafe` blocks, it should just use one of the debugger/approved standard library "trust me" functions (which would presumably be well-debugged). This would be quite a project, though... even when based on existing code.
_______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev