3 ms·
The question isn't why does the function decleration need to have &mut, it's why does the call site need to have &mut? as in assume you had: fn reset(p: &mut P
by kllrnohj 9y ago
The question isn't why does the function decleration need to have &mut, it's why does the call site need to have &mut?
as in assume you had:
fn reset(p: &mut Point) { p.x = 0; p.y = 0; }
Why can't this be called like so:
reset(&some_point);
rather than needing to say
reset(&mut some_point);
To some extent it's nice that the callsite must document the behavior visually, but its more forcing a style guide rather than anything that's required to compile & work.
- phaylon 9y agoYou can implement traits for both kinds of references, so a function might accept both.
- johncolanduoni 9y agoThe same thing can still happen with Deref coercions or type inference, so this is something the compiler already has to deal with.
- phaylon 9y agoI'm not sure what you mean. Can you give an example?
- johncolanduoni 9y agoIf struct A implements trait S and trait T, and there are two functions fn foo(x: &S); fn foo(y: &T); in scope, then the compiler needs you to disambiguate foo(&a) if a: A. This isn't a whole lot different than disambiguating the same expression if the functions are: fn foo(x: &A); fn foo(x: &mut A);
- saghm 9y agoWhen you use `&mut some_point`, (i.e. immutably borrow "some_point"), the compiler requires that "some_point" is not borrowed anywhere else at the same time. In order to enforce that invariant, it needs to know what borrows are mutable and what borrows are immutable. Perhaps what you're wondering is "why can't the compiler infer when a borrow needs to be mutable instead of having the programmer specify it"? I can't say for certain what the answer to this is, but my guess is that it would be rather expensive. Consider this example (reusing the "add" function from above): let mut foo = Point { x: 1, y: 2 }; let bar = &foo; add(&foo, &foo); ... // Much later reset(bar); Under the proposed "mutable reference inference" rules, should this compile? It's not necessarily trivial to determine this (especially if the "..." contains a lot of code), but it should not, since `bar` must a be mutable borrow to be able to pass into `reset`, which means that the borrows of `foo` to pass to `add` shouldn't be allowed. This means that the compiler would have to a rather expensive lookahead to determine whether any borrows are valid (and some people already complain that Rust compiles too slowly!). Forcing users to specify when borrows are mutable makes the compilers job much easier, not to mention the readability benefits that comes from making mutability explicit.
- johncolanduoni 9y agoBorrow checking happens quite late in the compilation process. It has to, because it can't know the lifetimes of the borrows until all the functions are resolved (borrows are allowed to leave the scope of the call via requirements imposed by functions, even to the point of being required to be static). If this choice was made for technical reasons, this is not why. Considering how seriously Rust takes explicitness in general, I strongly suspect this was done purely for readability.
- deathanatos 9y ago> To some extent it's nice that the callsite must document the behavior visually, but its more forcing a style guide rather than anything that's required to compile & work. I've always figured that was the reason. It's immediately obvious at the call site that a borrow is happening, and that it is a mutable borrow. Otherwise, if you wanted to know, you'd need to inspect each of the function's signatures that the variable is passed to. (Compare, perhaps, to C++ references, where it isn't apparent at the call site at all that your variable might change.)