How does Vec implement BorrowMut? - rust

I ran the following example in the standard library documentation, and there was a puzzle.
I found an implementation of the BorrowMut trait with Vec,
I don't understand how it works. For example, where the code below indicates that No.1 works, why doesn't No.2 work, what does the generic T do?
use std::borrow::BorrowMut;
fn check<T: BorrowMut<[i32]>>(mut v: T) {
assert_eq!(&mut [1, 2, 3], v.borrow_mut()); // ! no.1 can call, Why?
}
fn main() {
let v = vec![1, 2, 3];
// v.borrow_mut(); // ! no.2 Can't call,Why?
check(v);
}

The full error shown by rustc explains it pretty well. With emphasis added:
error[E0283]: type annotations needed
--> src/main.rs:9:7
|
9 | v.borrow_mut(); //! no.2 Can't call,Why?
| --^^^^^^^^^^--
| | |
| | cannot infer type for type parameter `Borrowed` declared on the trait `BorrowMut`
| this method call resolves to `&mut Borrowed`
| help: use the fully qualified path for the potential candidate: `<Vec<T> as BorrowMut<[T]>>::borrow_mut(v)`
|
= note: cannot satisfy `Vec<i32>: BorrowMut<_>`
BorrowMut can be implemented multiple times on a type. For example, both BorrowMut<Foo> and BorrowMut<Bar> could be implemented for Vec<i32>; in those examples, Foo and Bar take the place of the "type parameter Borrowed declared on the trait BorrowMut", as shown in its documentation (click "Show declaration").
In "no.1" you have specified that T: BorrowMut<[i32]>; since no other implementations of BorrowMut for T have been mentioned, the "type parameter Borrowed declared on the trait BorrowMut" can unambiguously be inferred to be [i32].
In "no.2", there is ambiguity over which implementation of BorrowMut you're after: even if no other implementations of BorrowMut for Vec<i32> are in scope right now, they could be lurking somewhere the compiler doesn't know about (pending being brought in-scope with a use statement); and even if no others exist right now, an upstream crate (namely, the std library) could add one in the future—and that would then break your code. Therefore the compiler asks you to remove the ambiguity by explicitly informing it which implementation you're after. It does this by reporting "type annotations needed", and even shows you how: "use the fully qualified path for the potential candidate: <Vec<T> as BorrowMut<[T]>>::borrow_mut(v)". We can do that here:
<Vec<i32> as BorrowMut<[i32]>>::borrow_mut(v)
However this won't work for a separate reason: Rust only performs deref coercion when calling with the . method syntax—when calling like this instead, you'd have to explicitly pass &mut v instead of v (I've filed an issue about this erroneous suggestion); and that still won't work in your case because v was not declared mutable.
The compiler also concluded with:
For more information about an error, try `rustc --explain E0283`.
Doing that would have displayed this extra information, which may also have helped.
Do please suggest how the error message could have explained the problem more clearly.
In actual fact, the compiler's suggestion above is more verbose than it requires to resolve the ambiguity in this case. You could also have resolved it without mentioning the type of v in either of these ways:
<dyn BorrowMut<[i32]>>::borrow_mut(&mut v)
BorrowMut::<[i32]>::borrow_mut(&mut v)
Also note that, in the case of Vec, you can obtain a mutable slice of its content (which is what this implementation of BorrowMut provides for you) via its intrinsic as_mut_slice method, indexing (via its implementation of std::ops::IndexMut), or calling upon std::ops::DerefMut::deref_mut whether explicitly or implicitly (i.e. using the dereference operator). Respectively:
v.as_mut_slice()
&mut v[..]
v.deref_mut() // DerefMut must be in scope, else qualify as above
&mut *v
Indeed, because of the dereferencing, &mut Vec also coerces to a mutable slice at coercion sites such as function arguments and let bindings—so you can often just use &mut v and Rust will do the rest for you.
See all approaches discussed in this answer on the Rust Playground.
Given that they all compile down to exactly the same code, which you use is really just a matter of preference. But, in order to keep the code as clear (and therefore maintainable) as possible, I would suggest that the indexing approach &mut v[..] most clearly and concisely indicates that you're taking a mutable slice over the whole of the vector.

Related

Why does Rust fail to correctly infer the type?

Why does this work fine:
let items = [1, 2, 3];
let mut cumulator = 0;
for next in items.iter() {
cumulator += next;
}
println!("Final {}", cumulator);
But this fail?:
let items = [1, 2, 3];
let mut cumulator = 0;
for next in items.iter() {
cumulator += next.pow(2);
}
println!("Final {}", cumulator);
Error on .pow(2):
no method named `pow` found for reference `&{integer}` in the current scope
method not found in `&{integer}`rustc (E0599)
My IDE identifies next as i32 and the first code example works fine. But the compiler has an issue the moment I reference next.pow() or any function on next . The compiler complains that next is an ambiguous integer type.
Sure, I can fix this by either explicitly declaring the array as i32[]. Or I can also use an interim variable before cumulator which is also explicitly declared i32. But these seem unnecessary and a bit clunky.
So why is compiler happy in the first case and not in the second?
Calling methods on objects is kind of funny, because it conveys zero information. That is, if I write
a + b
Then, even if Rust knows nothing about a and b, it can now assume that a is Add where the Rhs type is the type of b. We can refine the types and, hopefully, get more information down the road. Similarly, if I write foobar(), where foobar is a local variable, then Rust knows it has to be at least FnOnce.
However, if foo is a variable, and I write
foo.frobnicate()
Then Rust has no idea what to do with that. Is it an inherent impl on some type? Is it a trait function? It could be literally anything. If it's inherent, then it could even be in a module that we haven't imported, so we can't simply check everything that's in scope.
In your case, pow isn't even a trait function, it's actually several different functions. Even if it was a trait function, we couldn't say anything, because we don't, a priori, know which trait. So Rust sees next.pow(2) and bails out immediately, rather than trying to do something unexpected.
In your other case, Rust is able to infer the type. At the end of the function, all it knows about the type is that it's an {integer} on which Add is defined, and Rust has integer defaulting rules that kick in to turn that into i32, in the absence of any other information.
Could they have applied integer defaulting to next.pow(2)? Possibly, but I'm glad they didn't. Integers are already a special case in Rust (integers and floats are the only types with polymorphic literals), so minimizing the amount of special casing required by the compiler is, at least in my mind, a good thing. The defaulting rules kicked in in the first example because nothing caused it to bail out, and they would have in the second if it hadn't already encountered the bigger error condition of "calling an impl function on an unknown type".

Array cannot be indexed by RangeFull?

Consider the following example:
use std::ops::Index;
use std::ops::RangeFull;
fn f<T: Index<RangeFull>>(x: T) {}
fn main() {
let x: [i32; 4] = [0, 1, 2, 3];
f(x);
}
Upon calling f(x), I get an error:
error[E0277]: the type `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
--> src/main.rs:8:5
|
8 | f(x);
| ^ `[i32; 4]` cannot be indexed by `std::ops::RangeFull`
|
= help: the trait `std::ops::Index<std::ops::RangeFull>` is not implemented for `[i32; 4]`
note: required by `f`
--> src/main.rs:4:1
|
4 | fn f<T: Index<RangeFull>>(x: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I am confused. I can obviously write, for example, let y = x[..];. Does this not mean indexing x with RangeFull? Are arrays somehow special in this regard?
As you can see in the documentation for the primitive array type, Index<…> is not directly implemented for arrays. This is partly because it would currently be impossible to provide blanket implementations for all array sizes, but mainly because it's not necessary; the implementation for slices is sufficient for most purposes.
The expression x[..] is translated to *std::ops::Index::index(&x, ..) by the compiler, which in turn is evaluated according to the usual method call semantics. Since there is no implementation of Index<RangeFull> for arrays, the compiler repeatedly dereferences &x and performs an unsized coercion at the end, eventually finding the implementation of Index<RangeFull> for [i32].
The process of calling a generic function, like f() in your example, is different from method call semantics. The compiler first infers what T is based on the argument you are passing; in this case T is inferred to be [i32; 4]. In the next step, the compiler verifies whether T satisfies the trait bounds, and since it doesn't, you get an error message.
If we want to make your code work, we need to make sure to pass a slice to f(). Since a slice is unsized, we need to pass it by reference, so we need to define f() like this:
fn f<T: ?Sized + Index<RangeFull>>(_: &T) {}
The ?Sized is necessary since type parameters receive an implicit Sized bound. When calling f(), we need to make sure T is actually inferred as [i32] rather than [i32; 4]. To this end, we can either explicitly specify T
f::<[_]>(&x);
or explicitly perform the unsized conversion before passing the argument, so the compiler infers the desired type:
f(&x as &[_]);
f(&x[..])

How does Rayon prevent the use of RefCell<T>, Cell<T> and Rc<T> between threads?

The Rayon documentation say it guarantees that using Rayon APIs will not introduce data races.
How can the compiler know that the method called by the closures is not sharing mutable state, for example RefCell<T> and Cell<T>, or using structs that are not thread-safe, for example Rc<T>?
I understand that core::marker::Sync marks types that are safe to share between threads but I don't understand how the Rayon type declarations and the compiler enforce it!
You actually answered your question yourself – all closures that need to be shared between threads need to be Sync, and Rayon's API simply requires them to be Sync via trait bounds. See for example the documentation of ParallelIterator::map(), which specifies the method as
fn map<F, R>(self, map_op: F) -> Map<Self, F> where
F: Fn(Self::Item) -> R + Sync + Send,
R: Send,
There isn't any deeper magic here – whenever Rayon uses a closure in a way that requires it to be Sync, e.g. by passing it on to a lower level API, Rayon restricts the corresponding parameter type with the Sync trait bound. This in turn makes sure that everything stored inside the closure is Sync, so you can't store any RefCell in the closure.
In cases like this, you can also ask the compiler for an explanation. As an example, if you try to compile this code
use std::cell::RefCell;
use rayon::prelude::*;
fn main() {
let c = RefCell::new(5);
let _ = [1, 2, 3]
.par_iter()
.map(|i| i * *c.borrow())
.sum();
}
you will get this error (playground)
error[E0277]: `std::cell::RefCell<i32>` cannot be shared between threads safely
--> src/main.rs:10:10
|
10 | .map(|i| i * *c.borrow())
| ^^^ `std::cell::RefCell<i32>` cannot be shared between threads safely
|
= help: within `[closure#src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`, the trait `std::marker::Sync` is not implemented for `std::cell::RefCell<i32>`
= note: required because it appears within the type `&std::cell::RefCell<i32>`
= note: required because it appears within the type `[closure#src/main.rs:10:14: 10:33 c:&std::cell::RefCell<i32>]`
While the compiler unfortunately does not directly mention the trait bound for the parameter of map(), it still points you to the relevant method, and explains that it expects the closure to be Sync, and the reason why it isn't.

Why doesn't `Box::into_raw` take `self` as parameter?

This simple program:
fn main() {
let b: Box<i32> = Box::new(1);
b.into_raw();
}
Produces this inconvenient error when compiled with Rust 1.12.0:
error: no method named `into_raw` found for type `Box<i32>` in the current scope
--> <anon>:3:7
|
3 | b.into_raw();
| ^^^^^^^^
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
= note: candidate #1 is defined in an impl for the type `Box<_>`
This is because into_raw is not defined to take self as parameter, but instead is defined as:
impl Box<T: ?Sized> {
fn into_raw(b: Box<T>) -> *mut T;
}
This seems inconvenient, and I cannot find a rationale.
So... why?
Because 99.995% of the time (statistic totally made up), you expect method calls to happen to the thing being pointed to, not to the pointer itself. As a result, the "smart pointer" types in Rust generally avoid doing anything to break that expectation. An obvious exception would be something like Rc/Arc implementing Clone directly.
Box implements Deref, which means that all methods that are enclosed by the Box are automatically made available; from the outside, Box<T> and T look and act the same.
If into_raw were a method instead of an associated function, it would shadow any into_raw method on the contained type.
There are other examples of these enhancing associated functions on Rc, such as downgrade or try_unwrap, or on Arc, such as make_mut.

What does _ mean in type errors in Rust?

I received this error:
error: mismatched types [E0308]
process(s);
^
help: run `rustc --explain E0308` to see a detailed explanation
note: expected type `&(u32, u32, image::Luma<u8>)`
note: found type `&mut (u32, u32, &mut _)`
but I do not understand what the _ means.
In Rust, the _ identifier is used when the name does not matter. This occurs in a few situations:
let _ = ...; is used to ignore the result of an expression (only necessary when said result is marked with the #[must_use] attribute)
In types, _ is used to elide types (either because you prefer to let the compiler infer it or because the compiler judges it does not matter)
Thus, in your case, the compiler has elided the type because it does not matter, so that you can focus on the specific reason of the error. It may be confusing, at first, but once used to it it's actually helpful, especially when types are hairy (very large).
The error is simple: you are mistaking references and values.
Your original signature expects: &(u32, u32, Type) but you pass &mut (u32, u32, &mut Type).
The difference in mutability does not matter (in this direction), however a &mut Type and a Type have very different memory structure and are not interchangeable.
The _ is just a placeholder that could mean anything, and helps to clarify the error message.
In this case, it's saying it was expecting an image::Luma<u8>, but it actually found a mutable reference (&mut) to something. It doesn't matter what that something is; it &mut <something> can never be matched with image::Luma<i>.
If instead it said ...found type &mut (u32, u32, &mut T: SomeTrait) or similar, I think it would be harder to zoom in to the immediate problem.
You can't pass a reference to a function that expects an copied (or moved) full object instead.

Resources