Rustコトハジメ

プログラミング言語Rustに関する情報をお届けします。

Why do Iterator methods take FnMut instead of Fn?

Rust iterator supports functional programming that is, it supports functions like map and fold

fn map<B, F>(self, f: F) -> Map<Self, F> where
    Self: Sized, F: FnMut(Self::Item) -> B,

fn fold<B, F>(mut self, init: B, mut f: F) -> B where
    Self: Sized, F: FnMut(B, Self::Item) -> B,

Map for example is a iterator adapter. If you are a Java programmer and familiar with Guava library of Google it is like TransformedIterator in the library but the difference is Rust version is statically dispatched and there is not runtime cost for abstraction:

https://www.rustforbeginners.com/entry/en/2019/01/04www.rustforbeginners.com

I will write about what is the iterator adapter in later posts but today let's have discuss about the type.

What made me surprised when I see the type is that every iterator methods, not only map or fold, take FnMut instead of Fn. Since the aim of the library is to support functional programming that is pure, it seems to me there is no reason to allow the closure to mutate the environment.

The harm of allowing the side-effects in closure is for example, users may write the code like this:

fn main() {
    let mut sum = 0;
    let v1 = vec![1,2,3,4,5,6,7,8,9,10];
    let v2: Vec<i32> = v1.iter().map(|&x| {
        sum += x;
        x * 2
    }).collect();
    
    println!("sum={},v2={:?}", sum, v2);
}

I don't see any case we want to write such a nasty code. If we want side-effects in closure it should be done with internal mutability.

Another harm is that the interface implies that the closure applies to iterator items in one-by-one manner. This may pull our legs if we consider automatically parallelize the code using Rayon for example and Rayon actually types the counterpart method with Fn:

impl<I, F, R> ParallelIterator for Map<I, F>
where
    I: ParallelIterator,
    F: Fn(I::Item) -> R + Sync + Send,
    R: Send,

So the simple question is how did Rust designers consider when they design this interface. If I find some article or discussion threads I will share you in another post.