Remove obsolete null checks from style guide#181703
Remove obsolete null checks from style guide#181703auto-submit[bot] merged 2 commits intoflutter:masterfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates code examples in the style guide to remove obsolete null checks, aligning them with modern null-safe Dart. The changes are generally good, but one of the examples is left in a state that is not valid under null safety. I've provided a suggestion to correct the example by using the required keyword for non-nullable named parameters, which makes the code valid and achieves the goal of removing the explicit null check.
Piinks
left a comment
There was a problem hiding this comment.
Thanks for contributing some tweaks here.
| TheType get theProperty => _theProperty; | ||
| TheType _theProperty; |
There was a problem hiding this comment.
I could see how TheType could be a nullable property. Maybe we should make it explicit as TheType?? I think it's a good example to have the assertion in the setter body.
There was a problem hiding this comment.
In this example _theProperty is non-nullable, but you're right that the property could just as easily have been created as a nullable one.
However, I don't think it's good to have the assertion in the setter body; based on how this example is currently written, there's no way for the non-nullable value to be null.
There was a problem hiding this comment.
Yes. What I was suggesting was that you update this to be an explicitly nullable type to remove the ambiguity and keep the assertion.
There was a problem hiding this comment.
Okay, so then it would look like this:
TheType? get theProperty => _theProperty;
TheType? _theProperty;
void set theProperty(TheType? value) {
assert(value != null);
if (_theProperty == value) {
return;
}
_theProperty = value;
markNeedsWhatever(); // the method to mark the object dirty
}This would work, though it has the downside of being a bit more verbose. (In my opinion, being concise & readable is even more important in the style guide than anywhere else in this repo.)
Is there a downside to how I have it currently?
There was a problem hiding this comment.
Similar to the other example, I would consider the intention of the guidance here. This is about providing guidelines for performing dirty checks in setters. Does this change improve on that guidance? IMO, I don't think verbosity is a bad thing in docs meant to educate for working on the framework.
There was a problem hiding this comment.
IMO, I don't think verbosity is a bad thing in docs meant to educate for working on the framework.
I suppose we could agree to disagree here. There's a good reason "TL;DR" is so prevalent throughout the internet: if something is more verbose, the opportunity cost of reading & understanding is higher, ergo people become less likely to do it. In the case of this example, removing irrelevant code is a straight improvement IMO.
I really appreciate the time you've spent helping me out here. Since this PR would require two approvals to merge, maybe now would be a good time for another reviewer to step in with a fresh perspective.
There was a problem hiding this comment.
There's a good reason "TL;DR" is so prevalent throughout the internet: if something is more verbose, the opportunity cost of reading & understanding is higher, ergo people become less likely to do it. In the case of this example, removing irrelevant code is a straight improvement IMO.
I am not sure this is really relevant. This is a change specifically within the context of the Flutter org. Not the internet at large. :)
I will leave this to another reviewer to make a pass. Honestly, I don't know this change is worth this much debate.
There was a problem hiding this comment.
I agree that this example should change one way or another, because the assertion is no longer necessary and could confuse people. Also, the assertion is not important to this section of the style guide. My interpretation of the two options are:
Option 1:
TheType _theProperty;
void set theProperty(TheType value) {
- assert(value != null);
if (_theProperty == value) {
return;
}
_theProperty = value;
markNeedsWhatever(); // the method to mark the object dirty
}Option 2:
-TheType _theProperty;
+TheType? _theProperty;
-void set theProperty(TheType value) {
+void set theProperty(TheType? value) {
assert(value != null);
if (_theProperty == value) {
return;
}
_theProperty = value;
markNeedsWhatever(); // the method to mark the object dirty
}I like option 1. Option 2 is oddly specific and could distract from the point of this section. You might do something like it if _theProperty was supposed to be null during initialization or something and then never nonnull again... but then why assert instead of making the setter nonnullable? These are questions that the reader shouldn't be thinking about :)
| /// The [bar] argument allows the baz to quux. | ||
| /// | ||
| /// The `baz` argument must be greater than zero. | ||
| Foo({ this.bar, int baz }) : assert(bar != null), assert(baz > 0); |
There was a problem hiding this comment.
These could also be nullable, the sample code here does not provide enough information to determine if they are or not. IMO, I think this one is ok as is.
There was a problem hiding this comment.
I disagree here as well: the best practice is to avoid null-asserts in constructors.
class Foo {
Foo({this.bar}) : assert(bar != null); // BAD
Object? bar;
}Let's say that bar is a nullable field but you still want the constructor argument to be non-nullable. You could do it like so:
class Foo {
Foo({required Object this.bar}); // GOOD
Object? bar;
}It's much better for null-safety to be enforced by a type annotation than by using an assert, since the latter makes it much easier for mistakes to go unnoticed until runtime.
There was a problem hiding this comment.
Right, I think we might be over-indexing on code that lacks enough context to actually suggest this.
There was a problem hiding this comment.
Fair enough haha
But the point I was trying to make is: validating a constructor argument with an assert(bar != null) is never a good practice, so I'd like this example to be changed to reflect that.
There was a problem hiding this comment.
I appreciate you want to make the code snippet as accurate as possible. Given that this code snippet is meant to facilitate guidance around documenting parameters, and not to illustrate best practices around unnecessary null-asserts, does this change improve on the intended guidance?
There was a problem hiding this comment.
Yes it does!
Originally, this example documentation said:
/// The [bar] argument must not be null.At the time it was written, there wasn't a good way to enforce that a non-null argument is passed into a class constructor, so the best practice was to include this advice where applicable.
But thanks to null safety, this advice is no longer warranted: setting the class member as non-nullable means that static analysis will enforce it.
There was a problem hiding this comment.
I think that assert(bar != null) should go since it is not best practice. I don't want to confuse users or LLMs that might read it.
The conversation in #181703 got me thinking about whether there were any `assert(value != null)` statements in our codebase that were written prior to Dart's null safety era and could be factored out. It turns out that there are! This PR updates a few setters so that incorrect `null` assignments are caught by static analysis instead of potentially going unnoticed until runtime. Co-authored-by: Victor Sanni <[email protected]>
justinmc
left a comment
There was a problem hiding this comment.
LGTM 👍 . I say let's update these to modern Dart and move on, no need to debate these too much. Even if the examples aren't perfect they will now avoid being outdated.
| TheType get theProperty => _theProperty; | ||
| TheType _theProperty; |
There was a problem hiding this comment.
I agree that this example should change one way or another, because the assertion is no longer necessary and could confuse people. Also, the assertion is not important to this section of the style guide. My interpretation of the two options are:
Option 1:
TheType _theProperty;
void set theProperty(TheType value) {
- assert(value != null);
if (_theProperty == value) {
return;
}
_theProperty = value;
markNeedsWhatever(); // the method to mark the object dirty
}Option 2:
-TheType _theProperty;
+TheType? _theProperty;
-void set theProperty(TheType value) {
+void set theProperty(TheType? value) {
assert(value != null);
if (_theProperty == value) {
return;
}
_theProperty = value;
markNeedsWhatever(); // the method to mark the object dirty
}I like option 1. Option 2 is oddly specific and could distract from the point of this section. You might do something like it if _theProperty was supposed to be null during initialization or something and then never nonnull again... but then why assert instead of making the setter nonnullable? These are questions that the reader shouldn't be thinking about :)
| /// The [bar] argument allows the baz to quux. | ||
| /// | ||
| /// The `baz` argument must be greater than zero. | ||
| Foo({ this.bar, int baz }) : assert(bar != null), assert(baz > 0); |
There was a problem hiding this comment.
I think that assert(bar != null) should go since it is not best practice. I don't want to confuse users or LLMs that might read it.
The conversation in flutter#181703 got me thinking about whether there were any `assert(value != null)` statements in our codebase that were written prior to Dart's null safety era and could be factored out. It turns out that there are! This PR updates a few setters so that incorrect `null` assignments are caught by static analysis instead of potentially going unnoticed until runtime. Co-authored-by: Victor Sanni <[email protected]>
The conversation in flutter#181703 got me thinking about whether there were any `assert(value != null)` statements in our codebase that were written prior to Dart's null safety era and could be factored out. It turns out that there are! This PR updates a few setters so that incorrect `null` assignments are caught by static analysis instead of potentially going unnoticed until runtime. Co-authored-by: Victor Sanni <[email protected]>
04cd59e to
c0ab8ae
Compare
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
c0ab8ae to
38ce8f7
Compare
flutter/flutter@d117642...dd64978 2026-03-18 [email protected] Roll Skia from 2fb5fa71eb12 to f0a13e5efbad (2 revisions) (flutter/flutter#183830) 2026-03-18 [email protected] Roll Skia from ae3d36cb9e29 to 2fb5fa71eb12 (3 revisions) (flutter/flutter#183823) 2026-03-18 [email protected] Linux reuse sibling (flutter/flutter#183653) 2026-03-18 [email protected] Roll Skia from 84a180a1fa80 to ae3d36cb9e29 (4 revisions) (flutter/flutter#183812) 2026-03-18 [email protected] fix(web): handle asynchronously disposed platform views (flutter/flutter#183666) 2026-03-17 [email protected] (Test cross-imports) Remove legacy Material import from sliver_constraints_test (flutter/flutter#183351) 2026-03-17 [email protected] Fix Android Studio pluginsPath when version is unknown (do not use 0.0) (flutter/flutter#182681) 2026-03-17 [email protected] Fixes animation glitch into bottom sheet (flutter/flutter#183303) 2026-03-17 [email protected] Handle#6537 second grouped test (flutter/flutter#182529) 2026-03-17 [email protected] Add a Clarification for the docs of suggestionsBuilder of SearchAnchor (flutter/flutter#183106) 2026-03-17 [email protected] Remove obsolete null checks from style guide (flutter/flutter#181703) 2026-03-17 [email protected] [Impeller] Do not delete the GL object in a HandleGLES if the handle has a cleanup callback (flutter/flutter#183561) 2026-03-17 [email protected] Encode source file patches as UTF-8 in the code formatter script (flutter/flutter#183761) 2026-03-17 [email protected] Fix widget inspector control layout and add safe area regression test (flutter/flutter#180789) 2026-03-17 [email protected] Reland "[Android] Add mechanism for setting Android engine flags via Android manifest (take 2)" (flutter/flutter#182522) 2026-03-17 [email protected] fix(web): fix crash in Skwasm when transferring non-transferable texture sources (flutter/flutter#183799) 2026-03-17 [email protected] Roll Skia from dba893a44d7a to 84a180a1fa80 (7 revisions) (flutter/flutter#183803) 2026-03-17 [email protected] Framework: Improve DropdownButton selectedItemBuilder assertion (flutter/flutter#183732) 2026-03-17 [email protected] Add mainAxisAlignment to NavigationRail (flutter/flutter#183514) 2026-03-17 [email protected] Update android triage process to not look at unassigned p1s every week (flutter/flutter#183805) 2026-03-17 [email protected] Adds macos impeller new gallery transition perf test. (flutter/flutter#183802) 2026-03-17 [email protected] fix(web_ui): move prepareToDraw after raster to improve concurrency and stability (flutter/flutter#183791) 2026-03-17 [email protected] [build] Generate debug info for assembly. (flutter/flutter#183425) 2026-03-17 [email protected] [web] Fix occasional failure to find Chrome tab (flutter/flutter#183737) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
A couple of the style guide examples were written prior to Dart's null safety era, so this PR aims to update those examples.
Test-exempt because it only affects the
.mdfile.