Patterns aren't allowed in methods without bodies?

Code that looks sensible to me is now flagged by Rust as deprecated:

pub trait Whaat {
    fn foo(&self, mut f: u32);
}

Why can't I require mutable arguments in traits?

Your code has the same behaviour as

    fn foo(&self, f: u32);

And the mut-less one is just more idiomatic

If you write it like that, you are not declaring the argument to be mutable. The argument is of type u32, which is being passed in by value, nothing is being passed in by reference. Instead, you are declaring the variable within the foo function referred to by f to be mutable. But since that's purely an implementation detail, there's no need to specify that in the signature of a trait method.

This particular issue is due to https://github.com/rust-lang/rust/pull/37378.

In general, patterns in trait methods are very restricted, and I kinda hate that: https://github.com/rust-lang/rfcs/pull/1685 :slight_smile:

I see. That was unintuitive, because I expected that the declaration in the trait has to be identical to the definition in the impl.

So now I have an odd case where Rust forbids mut in the trait, but demands it in my mutating impl.

Only the types has to match. The exact names of parameters and patterns doesn't matter at all.

You can think of

fn foo(&self, mut f: u32) { ... }

as a sugar for

fn foo(&self, f: u32) {
    let mut f = f;
    ...
}

So now your impl has the exact same signature as the trait. The mut is just an implementation detail.

2 Likes

It's a good thing, because the mut has no effect in the trait definition and thus it should not be there (it could only mislead).

2 Likes

Here, mut is a property of the binding, not the type. That's why we write let mut x: u32 = 5 and not let x: mut u32 = 5. Since you take f by value, whether it is mutable or not really is up to you in the body.

People have said this a couple of different ways, but I don't feel like any of the responses have been direct: the code you posted doesn't require the binding to be mutable. For example, this is a valid implementation, regardless of whether the trait says mut or not:

impl Whaat for u32 {
    fn foo(&self, f: u32) {
        if self != f { panic!() }
    }
}

Every implementation of Whaat can declare if f is mut for that particular implementation. You can't require that they all declare f to be mut (which doesn't really make sense as a requirement; as others have said its not a part of the type).

This is very different from & vs &mut.

2 Likes