A clippy lint to warn on default match binding modes

(Edited because moved post now lacks the original context:)

So not only would more Rustaceans like to see Clippy lints against pattern binding ergonomics/default binding modes, but apparently it’s not a flat “no” anymore on the part of its developers. Let’s discuss this here.

Original post:

The thing I find the most infuriating is that the lang team explicitly refuses to add a Clippy lint against using default binding modes “because we don’t lint away an RFCd feature”. Why can’t I have my types back?

1 Like

That was probably said in the heat of the moment, immediately after the feature was accepted.
Requiring to “remove” it at that point was basically questioning their authority, nobody likes that.

Clippy has some restriction lints for features that are old enough so that their acceptance is not perceived as a recent decision.
So if you ask politely again, there’s a chance.

There was actually some movement on that a while ago. See Linting and match ergonomics and Defensive programming clippy lint category. I tried to get the ball rolling a bit after those discussions, but IIRC on #clippy it was suggested to wait until after the 2018 edition was out. I just haven’t had the energy yet to start pushing again on that front.

1 Like

Speaking only for myself (not with a lang team hat on), I’d be happy to see such a lint. Clippy, unlike the compiler, already has many lints that effectively create “dialects” far more so than this would.

1 Like

Perhaps we can move that discussion to another thread?

1 Like

Yes, please. It’s off-topic for this thread.

@josh @phaylon @petrochenkov @H2CO3

I agree. It’s moved.

4 Likes

I am a big fan of sugar and ergonomics. They are indeed very important for a language: coding patterns must not be cumbersome to write, or else some people will not use them (e.g., error handling in C).

On the other hand, knowing the exact semantics of the code just from the looks of it (i.e., no magic tricks happening under the hood) is one of the best things a language has to offer, and definitely the thing I love about Rust the most: we have macros for the ergonomics, but we can expand macros and inspect the generated code to look behind the curtain sugar and know what the code is doing.

So, for instance, the following code pattern,

match x {
    | Some(inner) => Some(inner),
    | None => None,
}

used to be easily identified as the identity function of Option<_>.

  • (if we ignore the possibility of a coercion on the inner value)

Now, with match ergonomics, this can read-dereference a discriminant pointed to by a reference, returning a reference wrapped with that discriminant!

This operation is non-trivial enough for us programmers to deserve a tool to better spot it, such as an allow-by-default lint, either in the compiler itself, or within a third party tool such as clippy.

3 Likes

I don’t understand the emphasis here. It’s so safe to do that that we always mark references as dereferenceable in LLVM, because it’s allowed to do this spuriously.

4 Likes

I feel that the compiler being able to spuriously read-dereference is not the same as the programmer actually doing it.

My emphasis was on the fact that we are no longer working at the x level of indirection; that with match ergonomics we may be working at the *x level of indirection; that’s why I find legitimate that the programmers be given a tool to spot such things in a more automated way.

4 Likes

I noticed that all the three relevant discussions about linting against default binding modes have become stale, with people wanting it having been called “dissenters” (despite having cited some very valid and at least as concerning corner cases), but not much more happened. What’s a good way to revive these discussions in a more productive manner, and, ultimately, to bootstrap an initiative towards adding such lints to either Clippy or rustc?

I fancy type based reasoning just as much as the next person. In fact, I would even like to reason about side-effects through the type system. Therefore, the notion that I want to take away your types is just not something that makes sense to me.

However, the part I would like to understand better is why type based reasoning about references specifically inside match expressions in safe code are important to highlight to some. What are the problems that are hidden by default match bindings?

An issue on Clippy’s repo + a PR would probably be most productive?

2 Likes

First of all, I really don’t want to retread the same territory here. Default match bindings is, sadly, part of the stable language now, and no amount of discussion about it here will change that. Many of these issues have already been posted elsewhere. So, to be clear up front: I’m happy to summarize the issues to help improve understanding and awareness, but this is not the appropriate thread for a discussion or debate on those issues (unless it’s specifically towards improving the compiler or tooling to help avoid errors and enforce typing). The subject of this thread is implementing a lint to more strictly enforce matching types in some codebases. Suggestions welcome for other machinery that would help ensure the compiler strictly enforces matching types as well.

Whether you’re doing type-directed reasoning/development, or trying to avoid or track down bugs, or trying to maintain efficiency, you may well care whether you have a reference or an owned object. When the compiler flags something like "you have a T and you need a &T", I generally put a moment’s thought into whether the right fix involves adding a & or ref somewhere, or whether the right fix involves going back to where I declared a type and changing it to take a reference instead of an owned value.

This change, for many people, took away some of the feeling that the compiler is helping by providing type errors, and instead made us feel less supported by the compiler. Feeling safer allows coding more quickly and confidently.

When the compiler ignores whether I have a reference or an owned value, it prevents me from caring about that, and decides for me that I don’t get to care about that.

As an aside, this is one reason why I don’t actually mind if the compiler accepts a &mut T when it expected a &T; that doesn’t change a non-reference to a reference, it just says “I don’t plan to modify this”. I do, however, want the compiler to strictly enforce the difference between T and &T.

6 Likes

Default binding modes do not only apply in match expressions. But anyway, type-based reasoning about references seems extremely basic and equally important to me, since references and values behave very differently.

I also don’t see why we should only focus on safe code; the problem with not knowing whether something is a value or a reference seems even more pronounced to me in the context of unsafe code.

For example, these.

4 Likes