-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Improve symmetry when calling a function with a borrowed parameter #10504
Comments
I have also found this annoying for locally understanding a function let a = ~1;
foo(a) Does that function call move I think that an interesting exercise for this issue would be removing autoref/autoderef for function arguments. I have a feeling that the change would be incredibly painful and probably not worth it, but this is probably something that should at least be considered. The alternative would be let a = ~1;
foo(&*a) Which does look a bit silly, but it is clear to all who read it that the argument is not moved, but rather borrowed. I'm not personally a big fan of this syntax. Another idea of how to go about this would be to very clearly document this in the tutorial/manual. This may be done already, but I'm not sure how well autoref/autoderef is covered overall. |
👍 |
@alexcrichton I would be ok with either always requiring The problem is that in order to explain the current behavior (which is fundamental, even at an early stage), you have to explain borrowing, then the In contrast, if the behavior symmetrically required If the behavior symmetrically did not require Either of those are better than the current sometimes-coerces approach, I think. |
I would like to remove argument coercion -- well, specifically "autoborrowing." Nominating. |
Reading the comments and discussing with @wycats, I hadn't considered the possibility of extending the autoborrow to encompass Still, what I dislike most about the autoborrowing is that I can't tell from a call site when I am passing by value and when I am not. That is, I dislike seeing this:
because it looks to me like
and so I see that in fact |
Something else to consider if we extended autoref: what about It seems odd to me that And would we allow |
I've added this to the meeting agenda. |
Here's another similar issue I ran into today when trying to explain things to someone: use std::io::stdio::println;
struct Person{
first_name: ~str,
last_name: ~str
}
impl<'self> Person {
pub fn new(first: ~str, last: ~str) -> ~Person {
~Person{ first_name: first, last_name: last }
}
pub fn full_name(&self) -> ~str {
self.first_name + " " + self.last_name
}
pub fn get_first_name(&'self self) -> &'self str {
self.first_name
}
}
fn main() {
let person = Person::new(~"Tom", ~"Dale");
println(person.get_first_name());
println(person.full_name());
} In this case, the use of
The solution was to do: pub fn get_first_name(&'self self) -> &'self str {
self.first_name.as_slice()
} Since I have a As a side note, orthogonal to this point, |
I imagine it's just a typo, but
in the original bug is incorrect, |
Currently we coerce for arguments and struct field initializers. We ought to coerce in return expressions too. I'm not sure if there are other missing places. Worth opening a separate bug for return expression coercion, if one doesn't already exist. |
@nikomatsakis I rather liked the idea of the invariant you stated in a blog post a while back. Namely "you don’t have allocation unless you see a sigil". The example you gave, and the automatic coercion of arguments in general seems to break this which is unfortunate, and I think a good argument against the coercion. |
@asb I assume @nikomatsakis is only talking about coercion to a reference ( |
@alexcrichton @nikomatsakis The problem you raised, whether a function call moves a unique pointer or not is not explicit, is annoying. But I think the source of this problem is the implicit move semantic, auto-borrowing just intensifies it. If you want easy understandings of the flow of ownerships, then maybe we should make the move semantic explicit, just like C++'s std::move. I dislike the &* way, since it just makes the language more ugly, and borrowing a heavy burden. |
@wycats I try to explain why ~T can be automatically cast to &T but not T. Rust distinguishes between values and pointers, thus it is reasonable to cast a ~T (unique pointer) to a &T (borrowed pointer). In contrast, the cast from a T (value) to a pointer (&T) isn't that consistent in design, although we could consider this. In C++, a &T actually is an alias, so it makes sense to accept a T when requires a &T. |
Rust doesn't have copy constructors, so the alternative to not moving by default is not having the ability to copy types with destructors. |
On Tue, Nov 19, 2013 at 05:10:27PM -0800, lilac wrote:
We tried it and found it quite painful in practice. This blog post |
@nikomatsakis Right. I've followed that blog for a long time, thus have read the post you mentioned. The latest post http://smallcultfollowing.com/babysteps/blog/2013/11/20/parameter-coercion-in-rust/ is really good work, covering many aspects of this issue. I can't agree with "if we remove autoborrow the notational overhead will be too large" and "it’s not actually possible to reason about a function independently of its callees" any more. |
We need to decide what we're going to do for 1.0. P-backcompat-lang. |
I propose taking RFC rust-lang/rfcs#112 and doing nothing else. |
This will break code like: fn f(x: &mut int) {} let mut a = box 1i; f(a); Change it to: fn f(x: &mut int) {} let mut a = box 1i; f(&mut *a); RFC 33; issue rust-lang#10504. [breaking-change]
New RFC: rust-lang/rfcs#139 |
Nominating for closure in favor of #15349, which I believe adequately captures what we'd like to do here for 1.0. |
…blyxyas,xFrednet [`type_repetition_in_bounds`]: Don't lint on derived code fixes rust-lang#10504. changelog: [`type_repetition_in_bounds`]: Don't lint on derived code
Currently, if I have a function like this:
I can call it like this:
But not like this:
According to @alexcrichton, this is because the first example automatically coerces the ~World into a &~World, but the second example does not.
The lack of symmetry here is somewhat confusing, and makes it hard to understand (at least at first), how exactly borrowed pointers work with different callers.
The text was updated successfully, but these errors were encountered: