-
Notifications
You must be signed in to change notification settings - Fork 30
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
Remove the annoying const lints from flutter_lints #205
Comments
/fyi @dart-lang/language-team |
The language team has had discussions about the churn caused by a small modification that changes which maximal enclosing expression can be const. E.g., We tried to introduce an "auto-const" feature a long time ago, but we removed the feature again because there were too many difficulties with it. In particular, it's a very bad idea to define a language mechanism in terms of "do a specific thing unless it produces a compile-time error". Another difficulty is that an expression like This means that it is difficult to create automatic and smooth support for "keeping expressions as const as possible". Hence the irritation that motivates this issue. I think another implication of this is that it is not a very good idea for the maintainers of a package to say "let's turn these lints off for now, never write Does this matter when it comes to these lints? Would it be fine if we just end up having a lot fewer occurrences of |
I created dart-lang/language#4084 in order to push on the possible introduction of a mechanism that would (largely) eliminate the churn that motivates this issue. |
Yeah, I'd be very wary about any blanket statement like that. It's a tool. If used precisely, I'm sure it can improve some performance measures. It will likely reduce the number of allocations, if equivalent objects would otherwise be created multiple times, but it may also increase the total memory pressure by having a bunch of objects that are never GC'ed. If the objects are pre-created, it could hurt start-up time too. Native AoT has options. Web code compiled to JavaScript needs code to create the object either way, and then needs extra state to remember the canonicalized constants. Being able to use (A very optimizing compiler could potentially recognize that a class is immutable, its arguments are immutable, and nobody ever uses I'm a little surprised that it has no effect, but I'm not so surprised that the effect isn't big. |
Please see recent updates in flutter/flutter#149932 (comment) |
I give the proposal to remove the const lints a huge +1. I find using const everywhere where it is applicable to be one of the biggest if not the biggest annoyance in writing day-to-day Flutter. It's especially annoying in the scenario where I have a const return const Column(
children: [
Foo(),
Bar(),
Baz(baz: getBa...), // <- `getBaz` is not constant so autocomplete refuses to suggest it.
],
); I think efforts to make const lints not annoying/less annoying (eg the aforementioned All the above said, I think the burden of proof should be on the const lints to justify their existence and if they can't demonstrate a strong benefit, they should be opt-in lints, not opt out. We can remove the lints and then if we do find a way to make them not tedious, add them back in. That could be a good bit of thrash, but the odds that the tediousness gets resolved feels very low given the subtle edge cases involved. |
Isn't it possible to "relax" the analysis constraints, such that an autofix simply removes the DX wise that would imply that, on save, the consts are auto removed when erroneous, and added when an optimization can be set. The whole "problem" would disappear at that point, no more going back and forth looking for consts that may or may not be actually consts. EDIT. I just recognized I basically proposed what @caseycrogers just said 😆 But I disagree on one thing: why should there be a burden of proof on lints? There's nothing to prove: a |
@goderbauer just out of curiosity, why you'd rather remove the lint rules, than simply disable them? 🤔 |
Better in theory or even in synthetic benchmark doesn't necessarily translate to measurably better in practice. The benchmarks at the top of this issue show no measurable perf benefit in real world apps. Someone should have to prove that const is providing measurable benefit to many projects for the lints to stay opt out. Otherwise, they should be opt in. The more I think about it, I'm not even sure why we're bothering trying to improve dev ex around const if attempts to measure its real world impact show no measurable benefit. If we can't demonstrate benefit in real programs, let's just turn off the lints and move on? It's a bad use of dev resources. Can anyone make a compelling practical argument otherwise? Fwiw, we only have one production use case benchmarked. If we tested more and found that a lot of real world projects do benefit then that'd change things, but shouldn't we do those benchmarks before even bothering trying to improve const dev ex? |
@alefwd: I believe that what Goderbauer means here is to "remove them from our Flutter recommended lints", which is essentially no longer enabling them by default, as those lints are what Developers can still enable them if they want to by simply adding the lints to the |
'constantly nagging developers: "Make this const"'
|
why do you want them to begin with? also, adding const is a tiny fraction of the pain caused by this lint. and a solution that works for your workflow in your IDE is not universal and furthermore i dont recommend autofix to solve this problem because the linter will recommend something be const, then in subsequent iteration youre stuck with an invalid const that breaks autocomplete in your widget tree. its much better to iterate ignoring the lint and then running a fix all on the codebase before committing |
I like the idea that if something can be const, it will be automatically (in the context of this lint rule, and vscode automatic action on save) because without this rule, you will forget to make stuff const, and if for example main listview item, that will be drawn possibly in hundreds, is not const, and could be, it's huge performance lost. But I agree that mostly it doesn't matter, for performance, for example if simple text widget is const or not, and that for other IDE's it can piss off ppl. For me it works :) |
@lukepighetti if this could be solved at analysis-time, as I said above, it's a win win for everyone.
So nobody loses consts optimizations. |
This one could be of interest: dart-lang/sdk#56669 (comment). (I'm not quite sure I understand your comment correctly, @lucavenir, but I noted 'auto add of consts' and thought you were considering a mechanism whereby |
Yes, absolutely. Thanks.
Well, actually no. Let me simplify. Can this diagnostic message include an autofix which automaticall does what the "common fixes" paragraph suggests, i.e. replace with AFAIK there should be a difference: in the comment you've linked you state the analysis cannot tell if something should be Instead, I'm wondering if an auto fix of the above would suffice. Such auto fix, given that the analysis already knows something cannot be By the way, I love the |
That shouldn't be hard to do. Note, however, that it is only applicable to a constant variable declaration. This means that it won't be able to do anything about the main topic of this issue.
The auto fix could certainly do exactly the same thing in terms of source code transformation as the |
I raised this issue on a Flutter Spaces discussion earlier this year so it's great to be vindicated. Always prefer const should be removed because it causes people to not understand what const does and not use it conscientiously. In addition to the development overhead of the IDE yelling at you. Did you know that if you want a child widget to rebuild whenever the parent widget rebuilds, all you need to do is NOT mark it as const? Child widgets will automatically rebuild whenever the parent rebuilds, except if the child widget is marked as const. Because of the automatic lint rule, the child widget is automatically marked as const, which leads to many developers adding in additional state management libraries to notify children of parent widget changes. Lots of unnecessary code from a lack of understanding of what const is doing. As a personal testimonial to the benefit of removing this lint, I've disabled this lint since almost a year and a half ago and it's improved my development speed by at least 10%. |
Flutter will rebuild a child if the equality check returns false.
|
To be clear: The lints themselves are not going anywhere. People, that like them, will still be able to opt in to them in their There are probably other things we can do to make the |
Removing from the default set SGTM. |
I'm in favor of removing these from the default set too. Assuming there is a real-world performance benefit, I'd love to see us pursue something like @eernstg |
It looks that it would be best to turn off those lints by default, and than run dart fix with them turned on, before committing, but this is not beginner friendly at all xd |
This is dicey. There are some circumstances where you may have (intentionally or otherwise) relied on non-constness for an |
I'm 100% on board with "encourage
I ran into this myself recently—I thought giving AppBar a
True, though that only applies to objects with equality implementations. By default, the object's identity is used to determine equality: if you don't override the
This is true, since widgets don't override the class KeyedSubtree extends StatelessWidget {
KeyedSubtree({super.key, required this.child});
final Widget child;
bool operator ==(Object other) {
return other is KeyedSubtree
&& other.key == key
&& other.child == child;
}
} …evaluating There are a few ways to get around this, but the most straightforward is just to use |
Sorry about creating some semi-relevant noise on this issue. ;-) Just for the record, I do think it makes sense to remove those const-related lints from But it would also be hugely interesting and useful to have more precise information about the actual performance implications of different levels of |
I have no trong opinion about removing thise from I would definitely argue against adding them to If the reason was just performance, I'd say the difference has to be significant to be worth it. A more targeted lint, maybe only focusing on |
@mit-mit Michael for sure, thanks! On the package page I read:
so removing them from there, does it imply all of a sudden const is not a "good coding practice"? https://dart.dev/tools/linter-rules/all and then disable only the very few which are conflicting. Works like a charm, way better than any package out there IMHO |
No, I don't think you can negate the statement there and have it mean the opposite. The goal of the standard lints is to have a starting point for lints which represents a balance between good coding practices and the extra effort it puts on developers. While we want a high coding standard, we also want Dart to be approachable to new developers. The goal is specifically not to capture all possible app lints. We offer a high degree of customization with lints; so it's expected and perfectly reasonable to pick your own preferred set. |
While I don't really have a strong opinion about whether this lint should be in the box, I'm not sure the "real world" benchmark is a great representation of whether const makes a difference. It's mostly just benchmarking if const SizedBox and const EdgeInsets improve perf. As they are trivial widgets, you aren't really gaining much from making them const. There isn't even a single Text widget that is const in the sample because the text widgets are localized: I believe this points to a larger problem regardless of how the lint issue is decided. It's definitely a fact that reusing widget instances can improve performance, but it's also a fact that due to limitations in dart and flutter, it's hard in practice to use const in places where you'd really desire the widgets to be reused. If the conclusion is that in the real world you can't ever really make enough widgets const to be useful, then what is the point of having const widgets and flutter pushing people to make all widgets have const constructors in the first place? I believe this "real world" example, while it may not be a good benchmark for if const improves performance definitely shows why in the real world, the limitations that dart and flutter place on const really restrict how much mileage you can get out of it. |
Thanks all for the feedback on this issue! For FYI on our standard process for evolving the lint sets:
The discussion takes into account things like: whether the lint fits into our rubrics for For this proposal - because the lints have been enabled for quite a while in Since @goderbauer, @natebosch, @lrhn, and @jonahwilliams are all in agreement, we'll proceed forward w/ removing the 3 const lints from |
So hard to ignore a blue underline on vscode. But personally i don't have any benchmarks if or not the const modifier has app improvements especially that in most cases the app long list of data or state UI will be probably something from the backed and so can't be const. Just the few titles etc. But on another linting issue Why are UI classes forced to be imuttable and marking arguments passed as final yet when you pass a dynamic argument in the constructor it's definately not const. |
…ations, prefer_const_literals_to_create_immutables (#7688) This PR removes three const lints from package:flutter_lints: `prefer_const_constructors`, `prefer_const_declarations`, and `prefer_const_literals_to_create_immutables`. This PR does not rev the pubspec version. We want to stage this change out in coordination with package:lints; see dart-lang/lints#209. - dart-lang/lints#205 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] page, which explains my responsibilities. - [x] I read and followed the [relevant style guides] and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use `dart format`.) - [x] I signed the [CLA]. - [x] The title of the PR starts with the name of the package surrounded by square brackets, e.g. `[shared_preferences]` - [x] I [linked to at least one issue that this PR fixes] in the description above. - [x] I updated `pubspec.yaml` with an appropriate new version according to the [pub versioning philosophy], or this PR is [exempt from version changes]. - [x] I updated `CHANGELOG.md` to add a description of the change, [following repository CHANGELOG style], or this PR is [exempt from CHANGELOG changes]. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/packages/blob/main/CONTRIBUTING.md [Tree Hygiene]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md [relevant style guides]: https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style [CLA]: https://cla.developers.google.com/ [Discord]: https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md [linked to at least one issue that this PR fixes]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#overview [pub versioning philosophy]: https://dart.dev/tools/pub/versioning [exempt from version changes]: https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#version [following repository CHANGELOG style]: https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog-style [exempt from CHANGELOG changes]: https://github.com/flutter/flutter/blob/master/docs/ecosystem/contributing/README.md#changelog [test-exempt]: https://github.com/flutter/flutter/blob/master/docs/contributing/Tree-hygiene.md#tests
… 5.0.0 (#156011) - update flutter create generated projects to use package:flutter_lints 5.0.0; this is a follow-up to publishing `package:flutter_lints` 5.0.0 - related to dart-lang/lints#205 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This will lead to issue flutter/flutter#144511, whole page will rebuild because |
I appreciate the rationale behind removing the const-related lints to improve developer experience, but I have concerns about how this change could impact real-world performance, especially with complex navigation scenarios. For example, I've encountered an issue with By removing these lints, there’s a risk that developers may unknowingly introduce inefficiencies in their apps, leading to increased rebuilds and poorer performance. While I understand that developers can opt back into these lints, having them enabled by default serves as a helpful reminder to follow best practices that can optimise performance. Could we consider an alternative solution, like making these lints part of a "performance-focused" set, rather than removing them entirely? This way, teams that care about optimisations can still benefit from them without sacrificing developer experience. |
Can you perf benchmark this? Would be interesting to see if this actually matters because the core insight driving this decision was everyone assumed the excess build calls were affecting perf when, at least for the benchmarked scenario, it turned out they weren't. If it's not user perceivable, who cares? If it is user perceivable, then that's makes a good case for having the lint on. But when the decision was being made literally no one bothered demonstrating that there was an actual real world user perceivable impact so we were left with no supporting evidence. But also, devs can just turn on the lint on an individual basis if they want it on and there's only so much hassle we should put all devs through? |
@sgaabdu4 reminds me of this discussion we're having flutter/flutter#156551 @caseycrogers Apologies in advance for commenting on an issue that's closed. Just had a bit of info to help my fellow developers. |
We loved the const lint, but now we must manually add it. It would have been really great if the developers who didn't like it could just turn it off. Many beginner developers don't use const most of the time, so this lint would have helped them create a habit of using const. |
The whole point of this thread was that we discovered this is a habit of questionable value-maybe developers shouldn't be in the habit of using const? At the very least it was insufficient evidenced to be on by default. |
In theory, const-ness should give apps a performance boost, but during development the lints enforcing const are constantly nagging developers: "Make this const" or "This cannot be const anymore". To evaluate whether we are making the right trade-offs here between annoyingness and performance we ran some benchmarks (see flutter/flutter#149932). The benchmarks have not shown sufficient evidence to suggest that there is a statistically significant difference in performance between const and nonconst for real world apps1. Given these results, the lints that constantly nag developers during development are not carrying their weight and I suggest we remove them from the
flutter_lints
set. People can still manually enable them for their app, if they like.Lints suggested for removal from the flutter_lints set (they can still be enabled manually):
prefer_const_constructors
prefer_const_literals_to_create_immutables
prefer_const_declarations
I suggest we keep the forth const lint (
prefer_const_constructors_in_immutables
) because it is very narrow in scope and generally doesn't cause any pain during development. It also enables downstream consumers to make their own choice of whether they want to create a const instance of a widget or not.Footnotes
In a contrived benchmark that did not represent real world usage in Flutter apps we were able to show that const in general can give you a small performance advantage. ↩
The text was updated successfully, but these errors were encountered: