Rayon: one code is compiled but similar other is not

hi, I’m rust newbie and I have some question about it.

I was interested in rayon and test some code using it.

fn main () {
    let v = [1,2,3,4,5];
    let p = &v;
    p.par_iter()
        .map(|&i| i + 3)
        .sum();
    sum_of_squares(&v);
}

and it emits this error

error[E0283]: type annotations required: cannot resolve `_: std::marker::Send`
  --> src/main.rs:14:10
   |
14 |         .sum();
   |          ^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0283`.
error: Could not compile `untitled`.

To learn more, run the command again with --verbose.

but it is very similar to rayon’s example code that compiled successfully

fn sum_of_squares(input: &[i32; 5]) -> i32 {
    input.par_iter() // <-- just change that!
        .map(|&i| i + 3)
        .sum()
}

I can’t find any difference from these two codes…
can you teach me why upper code was not compiled?

Your code does not compile because you’ve not specified what type you’re trying to sum into - you need to either store it in a variable with a type annotation:

let x: i32 = p.par_iter().map(|&i| i + 3).sum();

Or use a turbofish:

p.par_iter().map(|&i| i + 3).sum::<i32>();

The reason the original example didn’t require this is because the compiler could infer the type from the function signature of sum_of_squares - the function returns i32, so the type of sum must also be i32.

2 Likes

thanks!! now I understood why but error message still confusing me…

The sum() method is generic over any type which implements the std::marker::Send trait. That is where it comes from. The error message is telling you that the compiler couldn’t figure out unambiguously which concrete type to substitute for the generic type, and thus it asks you to disambiguate the call for it.

2 Likes

aha! now I got it. problem comes from using threading through rayon while doesn’t specifying type when collecting that from threads.
thanks a lot

1 Like
fn main ()
{
    [42_i32, 27].iter().cloned().sum();
}

gives

error[E0283]: type annotations required: cannot resolve `_: std::iter::Sum<i32>`
 --> src/main.rs:3:34
  |
3 |     [42_i32, 27].iter().cloned().sum();
  |                                  ^^^

As you can see, this is due to .sum() being generic in what it returns, both with rayon iterators and classic ones. The generic is then only bounded by the Sum trait,

Even if there is currently only one type that implements Sum<i32>, there could be others (e.g., we could have i64 : Sum<i32>), and without any other type annotation Rust cannot know whether it should choose the sum implementation that yields a i32 or another sum implementation.

2 Likes

Hmm, I wonder if we could get it to complain about needing the Sum trait first, rather than Send, if we reorder the declaration:

fn sum<S>(self) -> S
where
    S: Send + Sum<Self::Item> + Sum<S>,
3 Likes