Par_iter_mut problem

The following code doesn't compile while the same code with iter_mut instead of par_iter_mut compiles. Why do I need to implement the IntoParallelIterator trait, and how can I do that?
Thanks

use rayon::prelude::*;
trait E {fn eval(&self) -> f64;}
struct C<T:E> {
    d : T,
    v : f64}
type P<T> = Vec<C<T>>;
fn eval_test<T:E>(mut p:P<T>) -> P<T>{
    //p.iter_mut().for_each(|v| v.v=v.d.eval());
    p.par_iter_mut().for_each(|v| v.v= v.d.eval());
    return p;
}

The compiler tells you exactly what the problem is: &mut Vec<T> / &mut [T] doesn't implement that trait. If you go look up that impl in the docs, you can see it requires that the element type T be thread-safe (T: Send). So you have to specify that bound on your function.

You can't. You can't implement a foreign (non-crate-local) trait for a foreign (non-crate-local) type.

Thanks for the answer.
I am not yet absolutely comfortable with the use of traits. So

trait E : Send {
    fn eval(&self) -> f64;
}

is a way of solving the problem.
Thanks again.

FYI, The solution that @H2CO3 was suggesting AFAICT would be to put the bound onto the eval_test function, like fn eval_test<T:E+Send> (or alternatively separately as T: Send in a where clause.)

4 Likes

The difference is that trait E: Send means all E types must be thread-safe, whereas putting it on the function means it's only required if you're going to call that function.

Another consideration is that your function is only using the immutable &self, at least in this reduced example, so it could call par_iter() instead. That would shift your requirement to Sync, which could be easier to satisfy.

2 Likes

As far as I understand, when you declare a trait with a supertrait (like trait X: Y), then all where T: X clauses effectively become where T: X + Y automatically.

use rayon::prelude::*;

trait E {
    fn eval(&self) -> f64;
}

struct C<T: E> {
    d: T,
    v: f64,
}

type P<T> = Vec<C<T>>;

fn eval_test<T>(mut p: P<T>) -> P<T>
where
    T: E + Send, // if you had declared `trait E: Send`, then the `+ Send` would be implied here
{
    p.par_iter_mut().for_each(|v| v.v = v.d.eval());
    return p;
}

(Playground)

Interestingly, this only works with Supertraits (or where Self: Y bounds in the trait definition, which are just another syntax for supertraits), and not with any other bounds in the trait definition.