-
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
Add syntax to partially destructure self
in method signatures.
#83
Conversation
I'm personally more a fan of alternative 1 but there seems to be considerable opposition to making the borrow checker work across methods. This can lead to surprising errors since it is not clear at all which fields I'm allowed to use in a method. In this example, using The following alternative is a variation of the syntax proposed here and closer to alternative 1 but removes the compiler magic. Consider the following struct and functions: struct X {
a: T,
b: U,
c: V,
}
fn f(x: &mut X) {
g(x, &mut x.a);
}
fn g(x: &mut X, a: &mut T) {
/* function that doesn't use x.a */
} This doesn't work for the obvious reasons. fn g(x: &mut X{b, c}, a: &mut T) {
/* function that doesn't use x.a */
} This syntax would indicate that Some examples: fn f(x: &mut X) {
g(x, &mut x.a);
}
fn g(x: &mut X{b, c}, a: &mut T) {
h(x, a, &mut x.b);
}
fn h(x: &mut X{c}, a: &mut T, b: &mut U) {
/* ... */
} // impl X
fn f(&mut self) {
self.g(&mut self.a);
}
fn g(&mut self{b, c}, a: &mut A) {
/* ... */
} As you can see, fn f(x: &mut X) {
g(x, &mut x.a);
}
fn g(x: &X{b, mut c}, a: &mut A) {
/* b is immutable */
} I think this approach contains all the good parts of the current proposal while also extending it to arbitrary objects (not The only downside is that the syntax can get quite messy. However, consider that without this syntax you have to manually destructure the objects and pass the arguments individually which makes the function signatures and calls even longer. Edit: One could go so far as to add a new keyword to cover the most common cases: fn g(x: &mut X{not a}, a: &mut T) {
/* function that doesn't use x.a */
} |
I feel like this proposal will conflict quite severely with UFCS. Which is to say, |
Up to this point, patterns have been an internal implementation detail rather than part of the external API. Using this to perform partial borrows creates a backwards compatibility hazard and takes a step away from treating methods as normal functions. |
@kballard: @thestinger mentioned on IRC that you were trying to move away from treating methods as a special case but I hadn't heard of UFCS before. In this case you can forget about the original RFC. This leaves us with the "alternative" I proposed in the comment above which works for all function calls and not just methods. @thestinger: Are you against these partial borrows in general or just against the destructuring version I proposed in the original RFC? |
I think that if you want to propose something like this for arbitrary methods, what you really want to do is come up with some definition for a "struct slice". By that I mean some pseudo-type that means "fields x, y, z from struct Foo". Then you could use this to declare an argument as being of the type of that struct slice. Given that, whenever a struct is partially-moved or partially-borrowed, the compiler could use that to define the maximal valid struct slice (or maximally-borrowable struct slice, for taking Basically, I'm suggesting a way to make the type system aware of what you're trying to do, instead of having it be crazy pattern shenanigans. My proposed syntax for a "struct slice" would be That said, I feel like this is a post-1.0 sort of thing. |
The |
Well, what you're proposing seems to be just special destructuring stuff that the compiler uses to inform borrowck about whether it's safe to pass the value to the function. What I'm suggesting is that it be formalized into the type system properly. Although thinking again on my "struct slice" idea, it doesn't handle the case where a field of a struct is itself only partially-moved. Fixing that issue will probably make this a lot more complicated. |
"struct slicing" seems similar to "datasort refinements": http://smallcultfollowing.com/babysteps/blog/2012/08/24/datasort-refinements/ and rust-lang/rust#1679 |
Would a struct slice be a "derived type" in that its definition is based on another type, limiting access to its members but remembering the size of the original struct? Another view on the semantics of slicing structs could be in terms of set theory. Each struct slice is a subset of accessible members. In some ways this would be similar to traits. |
I think that this more-or-less falls out of the current plans for method dispatch and UFCS. Basically the |
No description provided.