-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
RFC: Raw Reform #365
RFC: Raw Reform #365
Conversation
Given |
Yes, though at least for the first one, |
Do we have this for normal raw pointers? (I. e. |
Doesn't this requires bounds checking? Thus effectively defeating the raw access advantage? |
@glaebhoerl Good catch! I think I caught them all. |
@arthurprs Perhaps I miscommunicated the intended behaviour, why do you expect bounds checking is required? Perhaps I didn't sufficiently clarify that raw slices are the |
@gankro nevermind, when I read the uint -> int change I had python indexes in mind (so -1 is the last element, -2 the before last ...) |
I've started implementing these changes in a branch as a sanity check, and to demonstrate the simplicity. One thing I've run into: Where previously you could call
Now you would need to do:
Hmm... perhaps some of these would be better of as free fn's in |
Ack, and |
Generally I think it's a bad idea for pointers to have inherent methods if they can avoid it, and that those should usually be free functions in |
👍 More concise unsafe code means fewer bugs. |
insertion_sort could actually be done more cleanly as: /// Rotates a slice one element to the right,
/// moving the last element to the first one and all other elements one place
/// forward. (i.e., [0,1,2,3] -> [3,0,1,2])
fn rotate_right<T>(s: &mut [T]) {
let len = s.len();
let s = s.as_raw_mut();
if len == 0 { return; }
unsafe {
let first = s.read(len-1);
s[1..].copy(s[..len-1]);
s.write(0, first);
}
}
fn insertion_sort<T>(v: &mut [T], compare: |&T, &T| -> Ordering) {
let len = v.len();
// 1 <= i < len;
for i in range(1, len) {
// j satisfies: 0 <= j <= i;
let mut j = i;
// `i` is in bounds.
let read_ptr = unsafe { v.unsafe_get(i) };
// find where to insert, we need to do strict <,
// rather than <=, to maintain stability.
// 0 <= j - 1 < len, so j - 1 is in bounds.
while j > 0 && compare(read_ptr,
unsafe { v.unsafe_get(j - 1) }) == Less {
j -= 1;
}
// `i` and `j` are in bounds, so [j, i+1) = [j, i] is valid.
rotate_right(unsafe { v.unsafe_slice_mut(j, i+1) });
}
} – we should support this style (although |
@reem When I drafted this up I was trying to apply the lesson's I'd learned working on collections stuff. Namely, that it's generally easier and safer to work and reason with objects in "modes". With collections we have the "iterator" mode, and with maps we now have "entry" mode. Unfortunately this translates poorly to references and rawptrs because we don't (and probably shouldn't ever) have I still think it would be nicer if when you have a ptr I'm leaning towards having the methods and the free fns, so that people can just do whatever is most natural. Possibly moving most if not all of the free functions to |
@arielb1 I've definitely mulled over the possibility of offering safe Otherwise, I'm not clear what you're suggesting. Every single one of your slicing operations is unchecked, and consequently riddled with unsafe's. It seems much cleaner at that point to simply say "okay, this is all unsafe" and just use raw slices. It doesn't seem very helpful to say exactly this subexpression is unsafe. But maybe that's just me? |
I think the main reason not to have Generally, we freely coerce from |
@gankro Ah, I think I understand now: you're saying that we don't (and shouldn't) automatically make the various methods of |
@arielb1 Also, you can just do this, if you really want:
Which is basically the same code-wise. Just more sigily. |
Given the above discussion, providing both free functions and methods probably makes sense (and it explains why these weren't just methods in the first place). I believe the motivation for having the |
I was discussing this with @kballard yesterday on IRC. They suggested that I'm not totally convinced by this argument, but I don't have particularly strong feelings. Removing it would reduce the API surface area with minimal ergonomic loss in my mind. It might also prevent novices from thinking Any thoughts? |
I think I agree with @kballard on this: I think the same is true for |
Free fns are mostly all back in the latest draft. Fleshed out some other stuff too. |
Wrapping the operations in individual unsafe-blocks is just a style thing – I put unsafe blocks around all places where safety invariants are temporarily being violated, so each occurrence unchecked indexing (which does not violate any invariant) gets placed in its own unsafe block. The primary point of my example is that it mostly uses unchecked indexing, rather than playing with raw pointers (other than within rotate). Raw pointers lose the aliasing guarantees, which just adds unneeded unsafety. I just noticed your proposal didn't talk about unchecked indexing, which is what we want in this case. Having official rotations (and "rotate-through-carry"-es) would be quite nice (should I post an RFC?). |
@arielb1: You're totally right. I strongly alluded to the fact that these operations would be unchecked in the earlier sections, but completely forgot to state this in the detailed design. I've now fixed this. I've also added your lifetime concern as a drawback to the proposal, as it is a very legitimate one! You can post an RFC, or prototype it out on discuss if you aren't totally comfortable with your current design. |
@gankro This is one reason that I think leaving |
``` | ||
trait RawSlice<T> { | ||
/// Gets the length of the rawslice | ||
fn len(self) -> uint; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of putting len()
in RawSlice<T>
, you should just implement Collection
on *const [T]
/*mut [T]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think Collection is going to survive #235, although that's a bit ambiguous.
What about slice_unchecked and slice_mut_unchecked? |
@arielb1 Can you clarify? |
Just noticed that the unsafe methods on |
Egh, just got reminded of |
Discussed with @pcwalton the viability of adding any lang stuff for new unsafe operators and it looks like that's a total no-go for 1.0; not out of the question for later, though! If this is indeed the case, then we need a migration plan. I propose adding the desired operators as unsafe named methods marked |
After some discussion with @aturon we've concluded that the most interesting bits can largely be hacked out in cargo while we wait for Rust to flesh out its operator overloading story. There's some useful ideas in here for stabilization, but we can revisit that with a different RFC. |
*const [T]
and*mut [T]
that provide parts of the slice and ptr API to better bridge thegap between the two.
unchecked slice manipulation.
provide more ergonomic ptr manipulation.
ptr
, and duplicate the rest as convenience methods onthe RawPtr extension traits.
unsafe
methods on slices andslice::raw
in favour of raw slices.them.
Rendered