-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Clarify text for unnecessary_final lint #58922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
/cc @davidmorgan |
Thanks @timsneath. There is nothing wrong with the lint itself. I understand why some teams may want to embrace this. The issue is the documentation, as you say.
I looked at this lint and was very confused. This isn't a reason to prefer Some teams may want to reassign variables as a matter of preference. For the record, I think that something like this would be better.
and perhaps
|
Hi Tim, Thanks :) this is a fun one. The Dart team--particularly Bob and Lasse, and they persuaded me, which is why I added this lint--prefer and recommend using The The Effective Dart rule you point to is talking about instance/global state not variables. It says exactly "fields and top-level variables final" ... locals should not be. Again, according to Bob ;) Unfortunately there is a tendency for people to pick up the "prefer final" lints with a sense that they are recommended and better--they are not. The recommended way is this lint. Unfortunately, the other lints got there first, and are far better established as a result. We might actually have to go with 'final' in google3 just for consistency--and against style recommendations. I don't think there's any nice resolution possible here; given the strength of feeling from Bob and Lasse I'm pretty sure we will never recommend "final", and given how much better established those lints are I don't think we can ever recommend "var", either. And in the end it just doesn't matter too much: what matters for the code is instance mutability, as called out in Effective Dart. Thanks Morgan |
@davidmorgan the issue is not the linter. The issue is the mistake in the documentation |
I will make a PR for the doco in the next couple of days |
Hi Christian, Those suggestions don't make sense I'm afraid; we definitely don't want to encourage Using We have repeatedly discussed whether to recommend Thanks Morgan |
@davidmorgan I wouldn't use this linter if you paid me, but you're not getting it. The current doco is completely incorrect and confusing
final does change the meaning of the code. You can frame the linter however you like. The point of the matter is that it reads like var is just as good as final and that's why this issue is here. |
Perhaps "change the meaning of the code" could be clarified. What was meant was, "does not change the meaning of the code from the compiler's point of view". The code compiles and runs exactly the same with It could be argued that it changes the intent of the code for a human reader, and perhaps this can be confused with "meaning"? Thanks. |
@davidmorgan the reader of this document is not concerned with how the compiler interprets it. What the reader takes away from this is that var and final mean the same thing, but they don't. 'var' means that the reference can be set multiple times while a 'final' declaration can only be set once. The documentation is very confusing for people reading the documentation. It is especially confusing for people new to Dart that may not have a full understanding of what the two keywords mean. |
Yes, the wording could be improved; suggestions welcome. |
I think there's a broader question of how to document the intent of linters here. I don't like this linter, but I understand the motivation. Many people new to Dart will use var more often than final and actually decide that it's better than final. They may decide to enforce that because of some arbitrary team decision, and that's fine. The question is how to phrase the intent of the linter without recommending it and possibly explaining that it goes against the Dart recommendations. To be honest, the linter doco should be more opinionated in order to match the tone of the Effective Dart guide. |
Using Using
Bob is the author and maintainer of Effective Dart, and he prefers As I said, I'm not aware of anyone on the Dart team who wants to recommend |
@davidmorgan well that totally changes the game then. That's certainly not clear in the linter. If the Dart team prefers var over final then both the related linters should mention that and put the case forward. |
But the point still stands that var and final are different and the documentation needs to clarify that. |
The individual lint docs generally don't talk about whether the lint is recommended; that's left to packages like https://github.com/dart-lang/lints to recommend a set. These then get a badge at the top of their page like 'style recommended'. FWIW I tend to agree; people link to lint documentation as if it's guidelines, when actually each lint documentation stands by itself. I think this has led to a lot of confusion over the years. I wonder if it would be worth putting a big banner at the top of lints that are not in any recommended set, to make it clear that people should not follow/quote them. Thanks. |
As a general comment, I think that the linter docs should give more context than they do. They often only give a line or two and they don't list the pros and cons of a given approach. For the record, I think they should link to the Effective Dart document where they relate to that, they should explain the intention of why someone created them in the first place, and they should explain the consensus in the Dart team. I don't treat them as gospel, but my assumption is that if the rule exists, and there is no opposite rule, the Dart team included the linter for a good reason. |
I 100% agree--I think many people assume that if a lint exists it's recommended; I see teams go through the whole list and try to enable as many as possible. Unfortunately there are lints that it is recommended to not enable. (vs being just not recommended, "optional"). That's why I was building a list of banned lints here but with the transition from Perhaps we should organize a "linter docs fixit" to raise the bar here. |
You will hate this then @davidmorgan https://pub.dev/packages/austerity I do hear where you're coming from. I also understand that some linters just directly contradict each other, and that some linters make code more verbose for some illusory idea of readability. But, I've combed through the linters and found that the vast majority are useful and help to guide people in the right direction. Anyway, I will try to make some suggestions on the text for this particular linter, but I would suggest that the docs get more opinionated about what the Dart team recommends. This is something that I and many others take very seriously. |
;) There is an important usability issue around the expectations for lints. Some lints correctly point out all places where a style guideline might apply, but can't tell you whether it does apply. If you always follow the lint then you are not following the guideline: you are ignoring the intended exceptions. If you intentionally enable these lints knowing that they should sometimes be ignored, that's fine. But as far as I know people usually don't differentiate the lints with false positives from the ones that are always correct. (We don't actually mark the ones with false positives anywhere, so it's not exactly easy; the That's a shame, because they are pointing out something useful. I have toyed with the idea of a new way to enable a lint, maybe call it "transitory" or "FYI". It fires once as you are writing the code, to say "here is something you might think about", then goes silent forever. We could then use it for lints like I like that idea, but have not had time to do anything with it :) |
@davidmorgan wrote
Here is one! ;-) I understand that some teams/developers may prioritize properties like simplicity ("just use However, the argument in favor of using
A developer who is reading the code in a function body where The latter will require a substantially larger number of brain cells to process when we read the code (not to mention when we're changing it). This means that This effect may very well be overlooked, because we are so familiar with the situation where lots of variables are effectively final (but not In summary, I'd certainly support anyone who is using a style where constraints like
As mentioned several times in previous comments, this is simply untrue. For example, a More importantly, the knowledge that a particular variable I think @timsneath's original proposal is a very good description of the main reason I've seen in this thread for abolishing local
|
Thanks Erik! I will update my future comment on the topic ;) FWIW I started this whole journey using I also looking at highlighting 'could be final' in the IDE, which would give the readability benefits for free--and had a local fork of the analyzer that did that. But, I was unable to land it. Unfortunately I think discussion around this topic has by now far exceeded the importance of the topic ... but that there is no path to ending the discussion. At this point I would be happy with us picking one of the two at random, recommending the corresponding lint, deleting the other, and auto updating all our code to match ;) ... more than anything else it's inconsistency that hurts us here, which is why we have https://dart.dev/guides/language/effective-dart/usage#do-follow-a-consistent-rule-for-var-and-final-on-local-variables ... but have been unable to apply that at a higher level ;)
Sounds good to me :) |
That's a very interesting way to get the same benefits in some reading situations! There's still one difference, though: If a function body has a In contrast, if You could say that the rationale here is something like the following: "Immutability of a local variable |
Thanks Erik. If a local scope is big enough that (re)assigment might be unclear, I prefer to split up the block. In this sense Of course you can use C computeC() {
final a = computeA();
return C(a, computeB(a));
} But then it really does seem like a distraction: it's carrying weight just in case the method grows big enough that reassignment isn't clear. Anyway, I no longer think it's worth arguing this to any specific conclusion, but if there is a way to reach any conclusion, I'm in favour; at this point I think nothing short of putting everyone with an opinion in a room and only letting them out when they pick one will suffice ;) |
Sorry, I having a hard time understanding the discussion here. What exactly is being discussed? This bug started with a request to update the description text of the So let's update that description. I suggest something like: "var is shorter, and thus preferred to keep code less verbose" |
We got a bit off topic ;) How about referencing Effective Dart? Use Per Effective Dart, there are two rules in wide use for And then the corresponding update for those lints to point to the style guide and back to this lint? Thanks. |
Yeah, I really like the cross linking here. Should we also clarify that the lint is only for local variables? The name |
Yes, definitely include the word 'local' anywhere it's unclear :) |
There's a lot of interest in improving the linter documentation along several dimensions. We are in conversation with @mit-mit and the documentation team (@MaryaBelanger and @atsansone) to discuss how to raise the bar here. Some of the rewriting is already underway. So please coordinate with us before doing any significant amount of information in this area.
I agree. I think that should be included in our discussion about improving the lint documentation.
We have talked about having such a mechanism. I'd love to talk with you about this more. (On a different thread.) |
All this discussion is important but it does take away from this doco just being wrong, confusing, and misleading
|
Draft PR here: dart-archive/linter#3832 |
Being just nitpicky " It may be confusing and misleading, and we should change it to something else, but it's not wrong. (If we had a three-letter |
@lrhn var is different to final. If you declare a local variable with var, you can assign a value more than once, but final stops you from assigning it more than once. |
As I mentioned here, this is not quite true: extension on int? {
void get foo => print('Final!');
}
extension on int {
void get foo => print('Not final!');
}
void main() {
final int? i1 = 1;
i1.foo; // 'Final!'
int? i2 = 1;
i2.foo; // 'Not final!'.
} |
At this point, it's probably worth pointing out that the two rules are not exact opposites of each other. This rule only kicks in if the value is never reassigned. But this rule kicks in any time you use It's not inconsistency. The first rule doesn't try to stop you from doing reassignments. You can reassign as much as you like if you switch to I doubt that either of these rules should be recommended. It's a team-by-team choice. |
The
unnecessary_final
lint contains a controversial explanation of its rationale.Specifically:
The historical context is here: dart-archive/linter#1827
While there are clearly divergent preferences around the use of
final
, it does change the meaning of the code (as theprefer_final_locals
lint explains). And whilevar
is shorter by two characters, that seems like a poor rationale for a lint. Readability is preferred over terseness, anyway.Lastly, Effective Dart has settled case law on the subject:
While we don't need to remove the rule, we should have explanatory text that is more accurate. For example, "some people prefer the simplicity of using
var
for all variables."The text was updated successfully, but these errors were encountered: