Why is the return type of Deref::deref itself a reference? - pointers

I was reading the docs for Rust's Deref trait:
pub trait Deref {
type Target: ?Sized;
fn deref(&self) -> &Self::Target;
}
The type signature for the deref function seems counter-intuitive to me; why is the return type a reference? If references implement this trait so they can be dereferenced, what effect would this have at all?
The only explanation that I can come up with is that references don't implement Deref, but are considered "primitively dereferenceable". However, how would a polymorphic function which would work for any dereferenceable type, including both Deref<T> and &T, be written then?

that references don't implement Deref
You can see all the types that implement Deref, and &T is in that list:
impl<'a, T> Deref for &'a T where T: ?Sized
The non-obvious thing is that there is syntactical sugar being applied when you use the * operator with something that implements Deref. Check out this small example:
use std::ops::Deref;
fn main() {
let s: String = "hello".into();
let _: () = Deref::deref(&s);
let _: () = *s;
}
error[E0308]: mismatched types
--> src/main.rs:5:17
|
5 | let _: () = Deref::deref(&s);
| ^^^^^^^^^^^^^^^^ expected (), found &str
|
= note: expected type `()`
found type `&str`
error[E0308]: mismatched types
--> src/main.rs:6:17
|
6 | let _: () = *s;
| ^^ expected (), found str
|
= note: expected type `()`
found type `str`
The explicit call to deref returns a &str, but the operator * returns a str. It's more like you are calling *Deref::deref(&s), ignoring the implied infinite recursion (see docs).
Xirdus is correct in saying
If deref returned a value, it would either be useless because it would always move out, or have semantics that drastically differ from every other function
Although "useless" is a bit strong; it would still be useful for types that implement Copy.
See also:
Why does asserting on the result of Deref::deref fail with a type mismatch?
Note that all of the above is effectively true for Index and IndexMut as well.

The compiler knows only how to dereference &-pointers - but it also knows that types that implement Deref trait have a deref() method that can be used to get an appropriate reference to something inside given object. If you dereference an object, what you actually do is first obtain the reference and only then dereference it.
If deref() returned a value, it would either be useless because it would always move out, or have semantics that drastically differ from every other function which is not nice.

Related

What is the concrete type of a future returned from `async fn`?

What type should I use for a vector that stores futures?
I tried to make multiple concurrent requests on the same URL and save all the futures into the vector to use with join_all.
If I don't set a type for the vector explicitly, everything works. I understand that Rust can find the proper type of a variable. CLion determines the vector type as Vec<dyn Future<Output = ()>>, but when I try to set the type by myself, it gives me an error:
error[E0277]: the size for values of type `dyn core::future::future::Future<Output = ()>` cannot be known at compilation time
--> src/lib.rs:15:23
|
15 | let mut requests: Vec<dyn Future<Output = ()>> = Vec::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `dyn core::future::future::Future<Output = ()>`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required by `std::vec::Vec`
I must declare the type as Vec<Pin<Box<dyn Future<Output=()>>>> which forces me to wrap result of function into requests.push(Pin::from(Box::new(request(i))));
use futures::future::join_all;
use std::future::Future;
use std::pin::Pin;
async fn request(n: i32) {
println!("Started: {}", n);
let response = reqwest::get("https://www.rust-lang.org")
.unwrap()
.text()
.unwrap();
println!("Completed: {}. Response: {}", n, &response[0..10]);
}
async fn main() {
let mut requests: Vec<dyn Future<Output = ()>> = Vec::new();
for i in 0..5 {
requests.push(request(i));
}
join_all(requests).await;
}
Which type it should be?
From the RFC:
The return type of an async function is a unique anonymous type generated by the compiler, similar to the type of a closure. You can think of this type as being like an enum, with one variant for every "yield point" of the function - the beginning of it, the await expressions, and every return. Each variant stores the state that is needed to be stored to resume control from that yield point.
When the function is called, this anonymous type is returned in its
initial state, which contains all of the arguments to this function.
You can't explicitly declare the concrete type of a future since it is an anonymous type. As an API user we only need to know that it implements std::futures::Future but this doesn't mean that we don't need a deeper knowledge of this anonymous type and it's implementation, it would be nice to have for grasping the concept.
CLion determines the vector type as Vec<dyn Future<Output = ()>>
This is a type hint, not the actual type, since compiler is not able to know the size of dyn Future<Output = ()>, it will not be compiled.
Pin<Box<_>>-ing a Future to declare an explicit type might not be a good idea. In your case it's not needed because the concrete types returned from async fn are identical. Letting the compiler infer the type will just be fine.
See also:
For various concrete return types :
How can I put an async function into a map in Rust?
Static & Dynamic dispatch : Trait Objects

Why does a &[T] argument also accept &Vec<T>?

I am working through the Rust book, namely the minigrep project. There I came across the following snippet:
fn main() {
let args: Vec<String> = env::args().collect();
let (query, filename) = parse_config(&args);
// --snip--
}
fn parse_config(args: &[String]) -> (&str, &str) {
let query = &args[1];
let filename = &args[2];
(query, filename)
}
The confusing piece for me is args: &[String]. If I replace it with args: &Vec<String>, it also works. My guess is that &[String] is a more general type annotation that matches not only &Vec<String>, but also some other types. Is that correct? If so, what other types are matched by [T]?
Generally speaking, [T] is a contiguous sequence and &[T] is a slice.
The reason why the compiler allows &[String] instead of &Vec<String> is that Vec<T> dereferences to [T]. This is called Deref coercion. It can be said that the former notation (in function parameters) is more general; it is also the preferred one. Further details about automatic dereferencing rules can be found in this question.

Why does asserting on the result of Deref::deref fail with a type mismatch?

The following is the Deref example from The Rust Programming Language except I've added another assertion.
Why does the assert_eq with the deref also equal 'a'? Why do I need a * once I've manually called deref?
use std::ops::Deref;
struct DerefExample<T> {
value: T,
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x.deref()); // this is true
// assert_eq!('a', x.deref()); // this is a compile error
assert_eq!('a', *x); // this is also true
println!("ok");
}
If I uncomment the line, I get this error:
error[E0308]: mismatched types
--> src/main.rs:18:5
|
18 | assert_eq!('a', x.deref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected char, found &char
|
= note: expected type `char`
found type `&char`
= help: here are some functions which might fulfill your needs:
- .to_ascii_lowercase()
- .to_ascii_uppercase()
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
First, let's spell out the generic types for your specific example: 'a' is char, so we have:
impl Deref for DerefExample<char> {
type Target = char;
fn deref(&self) -> &char {
&self.value
}
}
Notably, the return type of deref is a reference to a char. Thus it shouldn't be surprising that, when you use just x.deref(), the result is a &char rather than a char. Remember, at that point deref is just another normal method — it's just implicitly invoked as part of some language-provided special syntax. *x, for example, will call deref and dereference the result, when applicable. x.char_method() and fn_taking_char(&x) will also call deref some number of times and then do something further with the result.
Why does deref return a reference to begin with, you ask? Isn't that circular? Well, no, it isn't circular: it reduces library-defined smart pointers to the built-in type &T which the compiler already knows how to dereference. By returning a reference instead of a value, you avoid a copy/move (which may not always be possible!) and allow &*x (or &x when it's coerced) to refer to the actual char that DerefExample holds rather than a temporary copy.
See also:
Why is the return type of Deref::deref itself a reference?

Rust Vector of Traits: cast each trait

I have a problem casting a vector of traits into a vector of different traits.
Using the approach of Type-casting arrays/vectors in Rust , I basically tried the following:
trait ParentTrait {}
trait ChildTrait: ParentTrait {}
fn main() {
let mut children: Vec<Box<ChildTrait>> = vec![];
let parents = children.iter().map(|&e| e as Box<ParentTrait>);
}
Now this does not compile, it results in
error: the trait `core::kinds::Sized` is not implemented for the type `ChildTrait`
[...]
error: the trait `ParentTrait` is not implemented for the type `ChildTrait`
[...]
(The second errorline is buggy behaviour of the compiler, I guess?)
I tried various other flavors of References / Boxes and could not get it to work.
What am I doing wrong here,
is this even the correct approach with newer versions of rust (0.13)?
Trait objects are very strange beasts.
What is a Box<ChildTrait>? Box<T> is literally a wrapper for a *mut T. Therefore, a Box<ChildTrait> wraps a *mut ChildTrait. Because ChildTrait names a trait, ChildTrait is an object type. A pointer to an object type is represented by a pair of pointers: a pointer to the vtable for that trait and only that trait, and a pointer to the actual value.
When we inherit a trait from another trait, that doesn't mean we can obtain a pointer to the vtable for the first trait from a pointer to the vtable for the second trait. This is why the compiler complains that
the trait `ParentTrait` is not implemented for the type `ChildTrait`
We can, however, manually implement a trait for an object type. Because object types are unsized, we must first allow ParentTrait to be implemented for unsized types:
trait ParentTrait for Sized? {}
Then we can provide an impl of ParentTrait for the ChildTrait object type:
impl<'a> ParentTrait for ChildTrait+'a {}
If we try to compile now, we get different errors:
<anon>:9:40: 9:42 error: cannot move out of dereference of `&`-pointer
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
^~
<anon>:9:41: 9:42 note: attempting to move value to here
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
^
<anon>:9:41: 9:42 help: to prevent the move, use `ref e` or `ref mut e` to capture value by reference
<anon>:9 let parents = children.iter().map(|&e| e as Box<ParentTrait>);
We can use into_iter instead of iter to consume the initial Vec:
fn main() {
let mut children: Vec<Box<ChildTrait>> = vec![];
let parents = children.into_iter().map(|e| e as Box<ParentTrait>);
}
But then we get an internal compiler error:
error: internal compiler error: trying to take the sizing type of ChildTrait, an unsized type
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html
note: run with `RUST_BACKTRACE=1` for a backtrace
task 'rustc' panicked at 'Box<Any>', /build/rust-git/src/rust/src/libsyntax/diagnostic.rs:175
The same error also occurs with this code:
fn main() {
let mut children: Vec<Box<ChildTrait>> = vec![];
let parents = children.iter().map(|e| &**e as &ParentTrait);
}
At this point, I don't know if, after fixing the ICE, this would compile successfully or not.

Why can't I reuse a funtion's borrowed pointer

I don't understand why rustc gives me this error error: use of moved value: 'f' at compile time, with the following code:
fn inner(f: &fn(&mut int)) {
let mut a = ~1;
f(a);
}
fn borrow(b: &mut int, f: &fn(&mut int)) {
f(b);
f(b); // can reuse borrowed variable
inner(f); // shouldn't f be borrowed?
// Why can't I reuse the borrowed reference to a function?
// ** error: use of moved value: `f` **
//f(b);
}
fn main() {
let mut a = ~1;
print!("{}", (*a));
borrow(a, |x: &mut int| *x+=1);
print!("{}", (*a));
}
I want to reuse the closure after I pass it as argument to another function. I am not sure if it is a copyable or a stack closure, is there a way to tell?
That snippet was for rustc 0.8. I managed to compile a different version of the code with the latest rustc (master: g67aca9c), changing the &fn(&mut int) to a plain fn(&mut int) and using normal functions instead of a closure, but how can I get this to work with a closure?
The fact of the matter is that &fn is not actually a borrowed pointer in the normal sense. It's a closure type. In master, the function types have been fixed up a lot and the syntax for such things has changed to |&mut int|—if you wanted a borrowed pointer to a function, for the present you need to type it &(fn (...)) (&fn is marked obsolete syntax for now, to help people migrating away from it, because it's a completely distinct type).
But for closures, you can then go passing them around by reference: &|&mut int|.

Resources