Rust's 'as' is a general cast. It will try to do something reasonable to get from one type to the other, but while a few of the casts are totally unremarkable, some others open up too much opportunity to blow your feet off in my opinion (and I am not alone). Most obviously casting from a larger to a smaller integer is silently truncating. Sometimes, often even, this is what you intended, sometimes it's unimportant, but once in a while it's a trap.
Obviously it's nothing compared to the landmines in some languages, but I think there's room to teach safer options here, warn for and eventually (in a future edition) prohibit the narrowing cast.
#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
This might be too annoying for some people, but you can choose to allow ones that don't matter and keep the rest.Notably: it will warn for as truncation, integer arithmetic (a+b can panic or overflow; use checked_/wrapping_/saturating_), calling a function in unwrap_or, etc.
Lints: https://rust-lang.github.io/rust-clippy/master/index.html
let _ = mutex.lock(); // un-used, un-named 'hole' variable
let _a = mutex.lock(); // un-used, but named 'hole' variable
You might use this when the lock is essentially virtual, guarding something that isn't a data object. The first line will immediately drop the lockguard, while the second will leave it existing until the end of the scope. It's fairly subtle that this is the case.Where I actually ran into this was with a profiling timer object that was returning suspiciously short timings. But it could just as easily have been a critical section of some sort.
There's a correct warning if call lock() without using the result, because it has the must-use annotation, but if we throw it into _ the compiler is satisfied even though that's definitely not what a Mutex guard is for.
error: non-binding let on a synchronization lock
--> src/main.rs:5:5
|
5 | let _ = m.lock();
| ^^^^^^^^^^^^^^^^^
|
= note: `#[deny(clippy::let_underscore_lock)]` on by default
= help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop`
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock
Clippy is a third party tool, but highly recommended because of things like this. I would like to see this lint uplifted into rustc.Secondly, yes, I think should be uplifted. I'd even argue for default deny because I can't think of a reason you would want this behaviour and yet not find this more explicit phrasing more maintainable:
let guard = m.lock();
Mutex::unlock(guard); // We don't hold the guard, just touch and go
[I'm assuming anybody who actually wants this would prefer Mutex::unlock() over drop() because it says what's going on, and if they care that they can't write this in stable their effort would be appreciated pushing Mutex::unlock stabilisation rather than blocking a default-deny]I like the idea of these sorts of "drop-with-semantics" functions, but in practice until/unless they add a way to `impl !Drop` (or maybe `#[deprecated]` on a trait impl so you can add a deprecation note on your `impl Drop`) on a type, I'm not sure they're worth it.
Also, imo, that's probably a clippy lint that should be promoted to a built-in.
I hope future languages have even fewer. Here’s hoping!