Why is it necessary to add redundant trait bounds even though my trait uses those same traits as bounds? - rust

I have been trying to code a trait which requires a type to implement Add (and further down the line other operations for vector spaces) with itself as well as among its references. The following is a small example, illustrating the problem I ran into:
use std::ops::Add;
#[derive(Debug)]
struct MyVec<T>(Vec<T>);
impl<'a, 'b, T: Copy + Add> Add<&'a MyVec<T>> for &'b MyVec<T> {
type Output = MyVec<T::Output>;
fn add(self, other: &'a MyVec<T>) -> Self::Output {
/* ... */
}
}
impl<'a, T: Copy + Add> Add<MyVec<T>> for &'a MyVec<T> {
/* ... */
}
impl<'a, T: Copy + Add> Add<&'a MyVec<T>> for MyVec<T> {
/* ... */
}
impl<T: Copy + Add> Add<MyVec<T>> for MyVec<T> {
/* ... */
}
trait Addable: Add<Self, Output = Self>
where
Self: Sized,
for<'a> &'a Self: Add<Self, Output = Self>,
for<'b> Self: Add<&'b Self, Output = Self>,
for<'a, 'b> &'a Self: Add<&'b Self, Output = Self>,
{
}
impl<T: Copy + Add<Output = T>> Addable for MyVec<T> {}
fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
x + y
}
fn main() {
let v = MyVec(vec![1, 2, 3]);
let w = MyVec(vec![2, 4, 6]);
println!("{:?}", add_stuff(&v, &w));
}
I use the newtype pattern to create an alias of Vec so I can implement a foreign trait (Add) on a foreign struct (Vec).
I implement Add for MyVec and its references. The associated type Output is always the (unreferenced) MyVec. The latter three impls are implemented in terms of the first.
Addable is the central trait that I want to demo. Things that are addable should allow themselves and their references to be added with the result being Self. Particularly, in add_stuff I want the expression x + y + x to be valid where x + y gives a non-ref which can be added with x (which has not been moved out of, because it's a ref) to produce another non-ref.
I don't get any complaints from the compiler regarding the implementation of the Addable trait on MyVec. Specifically, the compiler seems to recognize that the above impls satisfy the bounds in the where clause.
However, I get the following compiler errors:
error[E0277]: the trait bound `for<'a> &'a T: std::ops::Add<T>` is not satisfied
--> src/main.rs:33:1
|
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | | x + y
35 | | }
| |_^ no implementation for `&'a T + T`
|
= help: the trait `for<'a> std::ops::Add<T>` is not implemented for `&'a T`
= help: consider adding a `where for<'a> &'a T: std::ops::Add<T>` bound
= note: required by `Addable`
error[E0277]: the trait bound `for<'a, 'b> &'a T: std::ops::Add<&'b T>` is not satisfied
--> src/main.rs:33:1
|
33 | / fn add_stuff<'a, 'b, T: Addable>(x: &'a T, y: &'b T) -> T {
34 | | x + y
35 | | }
| |_^ no implementation for `&'a T + &'b T`
|
= help: the trait `for<'a, 'b> std::ops::Add<&'b T>` is not implemented for `&'a T`
= help: consider adding a `where for<'a, 'b> &'a T: std::ops::Add<&'b T>` bound
= note: required by `Addable`
This can be fixed by amending the add_stuff function with a where clause as suggested by the compiler:
where
for<'c, 'd> &'c T: Add<&'d T, Output = T>,
for<'c> &'c T: Add<T, Output = T>,
I do not understand why this is necessary. I thought by specifying a bound in the definition of the trait I could rely on that bound being met for any type that implements that trait? Having to add these where clauses every time sort of defies the whole point of my Addable trait.
Googling brought up this GitHub issue which I don't understand fully but which might be related? That would suggest this is indeed a bug in Rust (which hasn't been fixed for a very long time).

You've hit a shortcoming of the Rust compiler as it currently is. RFC 2089 proposed to make it work as you expect, and was accepted in December 2017.
However, as of today, the feature isn't implemented. The tracking issue for the implementation hasn't seen much activity yet, so it appears implementation hasn't even started. It appears that some fundamental improvements to the compiler's trait bound handling are necessary before this particular feature can be efficiently implemented (search keyword: chalk).

Related

Unexpected error when using explicit lifetime in template argument in Rust [duplicate]

I have a trait Matrix and generic function semi_def<T: Matrix>(x: &T) that I would like to operate on that trait. The function requires an operator trait, say Mul, be implemented on T. However, I can't seem to make the lifetimes happy if one of the references is to a local variable. How do I write the lifetimes for references in the type constraint when one of them is just a local temporary reference?
use std::ops::Mul;
trait Matrix: Clone {
fn transpose(self) -> Self;
}
#[derive(Clone)]
struct DenseMatrix {
n_rows: usize,
n_columns: usize,
elements: Vec<f64>,
}
impl Matrix for DenseMatrix {
fn transpose(self) -> Self {
unimplemented!()
}
}
impl<'a, 'b> Mul<&'b DenseMatrix> for &'a DenseMatrix {
type Output = DenseMatrix;
fn mul(self, _rhs: &'b DenseMatrix) -> Self::Output {
unimplemented!()
}
}
fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
&'a T: Mul<&'a T, Output = T>,
{
&(*x).clone().transpose() * x
}
fn main() {}
which gives this error:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:31:6
|
31 | &(*x).clone().transpose() * x
| ^^^^^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
32 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 27:1...
--> src/main.rs:27:1
|
27 | / fn semi_def<'a, T: Matrix>(x: &'a T) -> T
28 | | where
29 | | &'a T: Mul<&'a T, Output = T>,
30 | | {
31 | | &(*x).clone().transpose() * x
32 | | }
| |_^
You need higher-ranked trait bounds (HRTBs), which are described in the advanced Rust book Rustonomicon and well as on Stack Overflow. They allow a type constraint to say that trait must be implemented not just for references with a particular lifetime but for any lifetime. They use the where for<> syntax. Here is the function definition that says an implementation of Mul is needed for any two references to T:
fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
for<'b, 'c> &'b T: Mul<&'c T, Output = T>,
{
&(*x).clone().transpose() * x
}
Because one of the references actually has the lifetime 'a, not a local lifetime, this could be written with a slightly looser constraint:
fn semi_def<'a, T: Matrix>(x: &'a T) -> T
where
for<'b> &'b T: Mul<&'a T, Output = T>,
{
&(*x).clone().transpose() * x
}
This Q&A is based off a question I asked on the Rust users mailing, which I cleaned up and brought over here for future Rustaceans.

Lifetime problems on implementing function that maps over an iterator using a HashMap

I tried to implement a function that maps over an iterator using a HashMap:
use std::collections::HashMap;
use std::hash::Hash;
/// Translates every element it gets using a map. In case the map does not help, it is mapped to
/// itself.
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
{
stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
playground
I get an error message for this code:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:11:16
|
11 | stream.map(|e: T| -> T { *map.get(&e).unwrap_or(&e) })
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 6:14...
--> src/lib.rs:6:14
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
= note: ...so that the types are compatible:
expected &&std::collections::HashMap<T, T>
found &&'a std::collections::HashMap<T, T>
note: but, the lifetime must be valid for the lifetime `'b` as defined on the function body at 6:18...
--> src/lib.rs:6:18
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^
note: ...so that return value is valid for the call
--> src/lib.rs:6:66
|
6 | fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a + 'b
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I have not figured out what is wrong or how I can solve it.
I have to guess, as you didn't include a MCVE. Your code doesn't compile, with lifetime errors on the surface. The function signature you probably meant is:
fn translate<'a, 'b, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'b,
T: Copy + Eq + Hash,
'b: 'a, // Read: "'b outlives 'a"
As S might outlive your return value, and it would still be valid.
However I do not see any advantages of this approach: A longer lifetime is always valid in place of a shorter one, you don't explicitly need to call that out. Simply use a single lifetime, like below.
fn translate<'a, S, T>(map: &'a HashMap<T, T>, stream: S) -> impl Iterator<Item = T> + 'a
where
S: Iterator<Item = T> + 'a,
T: Copy + Eq + Hash,
{
stream.map(move |e: T| -> T { *map.get(&e).unwrap_or(&e) })
}
As you see, you are also missing the move keyword, which your closure absolutely requires. Otherwise, it might outlive your map, which is owned by the function.
Still, this function is quite dense. If you only use it in a single place, maybe don't introduce it at all, and save some headaches?

Lifetime specifiers and generics in SFML

I'm trying to wrap my head around trait bounds and lifetime specifiers but I do not really get what is wrong here.
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, rect: &'a mut T)
where
T: Shape<'a> + Drawable,
{
window.clear(&Color::BLACK);
for x in 0..SCREEN_COLUMNS {
for y in 0..SCREEN_ROWS {
if chip.vid_mem[y][x] == 1 {
let x_pos = (x * SCALE) as f32;
let y_pos = (y * SCALE) as f32;
&mut rect.set_position((x_pos, y_pos));
window.draw(&rect);
}
}
}
}
error[E0277]: the trait bound `&'a mut T: sfml::graphics::Drawable` is not satisfied
--> src/main.rs:114:29
|
114 | window.draw(&rect);
| ^^^^^ the trait `sfml::graphics::Drawable` is not implemented for `&'a mut T`
|
= note: required for the cast to the object type `sfml::graphics::Drawable`
I don't really know how to specify my question any more than that since I have only been writing Rust for about 3 weeks and am still pretty new to the language.
the trait bound `&'a mut T: sfml::graphics::Drawable` is not satisfied
That's because it isn't — all you have required is that T implements Drawable:
T: Shape<'a> + Drawable,
T, &T and &mut T are all different types; just because T implements a trait doesn't mean that &mut T does. If you need to place a restriction on the mutable reference to a T, you can:
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, rect: &'a mut T)
where
T: Shape<'a>,
for <'a> &'a mut T: Drawable,
You might also be able to accept a T with the appropriate bounds:
fn render_screen<'a, T>(window: &mut RenderWindow, chip: &mut Chip, mut rect: T)
where
T: Shape<'a> + Drawable,
and then just pass in a &mut Foo wherever it is called.

Storing a closure with lifetimes in a struct

I'm trying to store closures in a Vec that is part of a struct. The closure is a factory function which receives 2 references as arguments and produces a trait object which stores the references the closure receives as arguments.
Because of that, the produced trait object has a lifetime that must not exceed the lifetime of the references. Also component_registrations will be accessed from multiple threads and is therefore wrapped in an Arc<Mutex>.
I tried implementing it but the compiler says that the generic parameter F of the register_component function doesn't satisfy the trait bound used in component_registrations.
This is the relevant part of the code:
use std::sync::Mutex;
use std::sync::Arc;
pub mod gl {
pub struct Gl();
}
pub struct ComponentRegistry<'a> {
gl: &'a gl::Gl
}
pub trait Component<'a> {
}
pub struct Application {
component_registrations: Arc<Mutex<Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b>> + Send + 'static>>>>
}
impl Application {
pub fn new() -> Application {
Application {
component_registrations: Arc::new(Mutex::new(vec![]))
}
}
pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
self.component_registrations.lock().unwrap().push(Box::new(register));
}
}
error[E0277]: the trait bound `for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not satisfied
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ the trait `for<'b> std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` is not implemented for `F`
|
= help: consider adding a `where for<'b> F: std::ops::Fn<(&'b ComponentRegistry<'b>, &'b gl::Gl)>` bound
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
error[E0271]: type mismatch resolving `for<'b> <F as std::ops::FnOnce<(&'b ComponentRegistry<'b>, &'b gl::Gl)>>::Output == std::boxed::Box<Component<'b>>`
--> src/main.rs:27:59
|
27 | self.component_registrations.lock().unwrap().push(Box::new(register));
| ^^^^^^^^^^^^^^^^^^ expected bound lifetime parameter 'b, found concrete lifetime
|
note: concrete lifetime that was found is the lifetime 'a as defined on the method body at 26:5
--> src/main.rs:26:5
|
26 | / pub fn register_component<'a, F>(&mut self, register: F) where F: Fn(&'a ComponentRegistry<'a>, &'a gl::Gl) -> Box<Component<'a>> + Send + 'static {
27 | | self.component_registrations.lock().unwrap().push(Box::new(register));
28 | | }
| |_____^
= note: required for the cast to the object type `for<'b> std::ops::Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> std::boxed::Box<Component<'b>> + std::marker::Send`
If you use a higher ranked lifetime when you define your component_registrations struct field, you should use a higher ranked lifetime for F as well.
Also, if you say Box<Component<'b>>, it really means Box<Component<'b> + 'static> (so the trait object can contain only owned data). What you really need is Box<Component<'b> + 'b>, which means it is a trait object that implements Component<'b> and it can also contain borrowed data which live at least as long as 'b.
The relevant part is
pub struct Application {
component_registrations: Vec<Box<for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static>>
}
impl Application {
pub fn register_component<F>(&mut self, register: F) where F: for<'b> Fn(&'b ComponentRegistry<'b>, &'b gl::Gl) -> Box<Component<'b> + 'b> + Send + 'static {
self.component_registrations.push(Box::new(register));
}
}
You can see the full example. Note, that I removed the Arc and Mutex types from your example since they were not relevant.

Rust generic AddAssign with references

A while ago I looked into writing a generic iterator for the Fibonacci sequence
that could accept both primitive numbers as well as custom types (such as
bignums). After failing to get a version working for both the primitive types
and bignums, I stumbled upon this question:
How to write a trait bound for adding two references of a generic type?
Which used so called Higher Ranked Trait Bounds to solve the problem with this
particular issue.
Now however, I'm trying to use a similar strategy to use the *_assign
operators instead. In particular, I'm trying to get something similar to this
working:
use std::ops::{Add, AddAssign};
fn add_test<'a, T>(x: &'a T, y: &'a T) -> T
where
for<'b> &'b T: Add<Output = T>,
{
x + y
}
fn add_assign_test<'a, T>(x: &'a mut T, y: &'a T) -> T
where
for<'b> &'b mut T: AddAssign<&'b T>,
T: Clone,
{
x += y;
x.clone()
}
fn main() {
println!("add_test()={}", add_test(&1, &2));
println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
}
add_test() works as expected but I'm unable to get add_assign_test() to work in a similar way. The errors I'm getting suggest that there might not actually exist an implementation for this kind of behaviour on the primitive types:
error[E0277]: the trait bound `for<'b> &'b mut _: std::ops::AddAssign<&'b _>` is not satisfied
--> src/main.rs:21:38
|
21 | println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
| ^^^^^^^^^^^^^^^ no implementation for `&'b mut _ += &'b _`
|
= help: the trait `for<'b> std::ops::AddAssign<&'b _>` is not implemented for `&'b mut _`
= note: required by `add_assign_test`
I could create a macro that creates implementations for these operators that actually takes references to the primitive types, but that seems a little wasteful. Is there any other way to achieve the same effect?
Just a tiny oversight in your code. Let's look at the trait:
pub trait AddAssign<Rhs = Self> {
fn add_assign(&mut self, rhs: Rhs);
}
The receiver of the method is already &mut self and not self. The reason that you had to do the extra work with Add is because it accepts self as receiver. For AddAssign this means: if a type T implements AddAssign, you can call the method add_assign() on a &mut T!
Thus, instead of writing:
where for <'b> &'b mut T: AddAssign<&'b T>,
... you would write:
where for <'b> T: AddAssign<&'b T>,
(No other line changed so far)
However, you notice that the code still won't compile:
error[E0277]: the trait bound `for<'b> {integer}: std::ops::AddAssign<&'b {integer}>` is not satisfied
--> src/main.rs:13:38
|
13 | println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
| ^^^^^^^^^^^^^^^ no implementation for `{integer} += &'b {integer}`
|
= help: the trait `for<'b> std::ops::AddAssign<&'b {integer}>` is not implemented for `{integer}`
= note: required by `add_assign_test`
The reason is simple: there is simply no implementation of AddAssign for primitive types which takes an immutable reference as rhs (Docs). I don't know if this is an oversight -- it could be worth opening an issue on the Rust repo.
To verify the above code works, I write my own type and implemented AddAssign appropriately: Playground.
Corrected the code snippet based on Lukas' reply:
use std::ops::{Add, AddAssign};
fn add_test<'a, T>(x: &'a T, y: &'a T) -> T
where
for<'b> &'b T: Add<Output = T>,
{
x + y
}
fn add_assign_test<'a, T>(x: &'a mut T, y: &'a T) -> T
where
for<'b> T: AddAssign<&'b T>,
T: Clone,
{
*x += y;
x.clone()
}
fn main() {
println!("add_test()={}", add_test(&1, &2));
println!("add_assign_test()={}", add_assign_test(&mut 2, &2));
}
It appears that this is an issue in Rust itself. There is currently a tracker for this issue.
Until this is fixed, there's two possible workarounds:
Create named-tuples for each primitives and implement OpAssign for those types instead. This does however force you to 'cast' all primitives to your custom type.
Duplicate the 'generic' code with specializations for the primitives.

Resources