Hacker News new | ask | show | jobs
by nauticacom 1644 days ago
I've genuinely never understood this one, especially as a flat-out error instead of a warning. When could not using a variable ever be a bug?
4 comments

That warning has caught bugs for me when I was copy and pasting code, or writing code on "autopilot". Usually it's pretty obvious mistakes though.

Unused variable warnings are a good idea, but making them hard errors is a language design mistake. Warnings are good because they allow programmers to quickly make changes and test things, while providing a reminder to clean things up in the end (which is why the "just use tooling that removes unused variables" response misses the point--when making quick temporary changes for debugging, you want the warnings as reminders to go back and undo the change). Additionally, warnings allow for adding helpful static analyses to the compiler over time without breaking existing code like introducing new errors does. As I recall, there were some cases in which Rust 1.0 accidentally didn't flag unused variables, which was fixable post 1.0 without breaking existing code precisely because it was a warning, not an error.

Pretty bold to call it a language design mistake so confidently, when you have Rust users committing warning-emitting code to their source control.

Does Rust emit warnings for cached compilation units?

Cargo doesn't enable warnings for crate dependencies, by design. In fact, it won't even emit them if those crates say #[deny(warnings)]--there's a special rustc flag called --cap-lints that it uses for this (RFC at [1]). The reason is that a lot of crates say #[deny(warnings)], and this was creating no end of backwards compatibility problems when new warnings were added.

There is an interesting thread with community consensus against the use of #[deny(warnings)] at [2]. The most important takeaway for me is that the right place to deny warnings is in CI. You don't want end users who compile your crate to be have their builds fail due to warnings, because they might be using a newer version of the compiler than you were. You don't want to fail developers' builds due to warnings while hacking on code, because of the overhead warnings-as-errors adds to the edit/compile/debug cycle. CI is the right place to deny warnings, because it prevents warnings from getting to the repository while avoiding the other downsides of warnings-as-errors.

[1]: https://rust-lang.github.io/rfcs/1193-cap-lints.html

[2]: https://www.reddit.com/r/rust/comments/f5xpib/psa_denywarnin...

Yes, users can misuse warnings by ignoring them in CI, but the ergonomic cost of forcing unused variables as errors is disproportionate in regard to this. This affects all users regardless of if they would deny warnings in CI, and leads to either removing/adding some code repeatedly so it compiles at all, or worse adding fake uses, defeating the purpose of the warning. I am using C++ with -Werror during development because it is the only way to keep my sanity (functions not returning a value in C++ is a warning), but it is an ergonomic disaster that I am happy to avoid when using Rust (where the right place to deny warnings is in CI).

I would agree that forcing uninitialised variables as errors is a design mistake.

I think it's reasonable for users to want a workflow that includes some mode where they can temporarily compile code that has unused variable, then check in code that does not have unused variables. The trouble is that if there's such a mode, people will just leave it on permanently. I don't have solutions, but I think it's worth trying to save people's workflows.

    foo := someDefaultValue
    if someCondition {
        foo := someMoreSpecificValue
    }
Whoops, accidentally created a fresh, unused variable in the nested scope instead of changing the value of the original variable.

I do that frighteningly often.

Seems to be more an indication that Go's variable declaration syntax is just not good.
Yeah, var/type name makes much more sense than ambiguity.
It happens. Hell, it even happens in Rust, i had one happen a few weeks ago that the warning lint caught. I had a rename and then added an inner scoped var of the old, previous name - but neglected to use that new var in that inner scope. Compiled fine, but was very much a bug.

Luckily though my Rust setup doesn't fail to compile with unused stuff, it just warns - and then on CI i have it reject all warnings.

I agree it's very frustrating not having a -dev flag or something less restrictive.

When you mistakenly used the wrong variable name instead, I suppose.
It is only useful in the very niche case that the incorrect variable name you're using is defined (otherwise you'd get an unknown identifier error) and the correct name you should have been using isn't used anywhere.

Would catch this:

  var a, b
  c = a + a // whoops, should have been a + b, compiler complains about unused b
Doesn't catch this:

  var a, b
  foo(a, b)
  c = a + a // whoops, should have been a + b, but still compiles
All in all, unused variables being errors is an awful feature that isn't very helpful in practice, at the cost of making experimentation a pain in the arse.

There is nothing that kills my state of flow more than having to comment a piece of code that is unreferenced, because the compiler complains, while I'm trying to hack and explore some idea.

In which case a warning would also do the trick, unless the compiler produces so many warnings that people stop caring.