Suggestion: "mut", like "let" keyword

Eh. When I see stuff like this I can’t help but feel that people are misplacing their enjoyment of immutability in general. Here is how I honestly feel about it:

  • Not being able to get a &mut U from a &T is one of the core principles of Rust.
  • Not being able to get a &mut U from an immutable T is an annoyance (when writing code) that, in my experience, is almost always correctly solved by adding a mut. But, it has two great payoffs:

First, it makes the unused_mut lint one of the top most useful bug-catching lints, right up there with unused bindings. Oftentimes I might know for instance that I want to collect some data from an iterator into a vector, and then sort it. Thanks to mut being required I now have it trained in me to write let mut vec: Vec<_> = in anticipation of the sort:

let mut vec = {
    things.iter()
        .some_long_and(complicated)
        .pipeline_of(iterator, adapters)
        .collect::<Vec<_>>()
};

but then after all of that, I often forget to finish what I started and actually call sort!

Second, reading the code after it is written, anybody who sees mut can expect that something will happen to the value after its initial assignment. (this is, of course, also thanks to the unused_mut lint)


I can contrive an example where adding mut is not the solution:

  fn ancient_function() {
      let items = {
          things.iter()
              .some_long_and(complicated)
              .pipeline_of(iterator, adapters)
              .collect::<Vec<_>>()
      };

+     items.sort();  // sort the output that gets printed
      print_report(&items);

      save_file(items);  // (note: expects items to be in original order)
  }

but to make a mistake like that seems… rather careless, enough so that I doubt that the author would notice it even after the minor speedbump presented by the "missing mut" error.

5 Likes