The 2 new lints in Dart 3.1

Alexey Inkin
Flutter Senior
Published in
3 min readAug 18, 2023

Dart 3.1 was released two days ago, and you can read the official announcement here. It did not list new lints, so let’s cover them here.

no_self_assignments

This lint covers the obviously unwanted things like

int n = 1;
n = n;

Self-assignments can get more complicated when a variable is shadowed if you do uncareful automated refactoring from this

int n = 1;

void setN(int newValue) {
n = newValue;
}

… to this:

int n = 1;

void setN(int n) { // Shadows the global variable
n = n;
}

To some extent, you are protected against that with an older parameter_assignments lint, but some do not turn it on. And it can’t help you when a global variable is shadowed by a class field.

Then there are more tangled cases when people assign an object’s getter to its setter just to trigger the setter’s logic, and this lint really helps to get things in order in those cases.

no_wildcard_variable_uses

We often need to accept a redundant value forced by a function signature. BuildContext in Flutter is a very common example:

return StreamBuilder(
stream: stream,
builder: (context, snapshot) {
// ... not actually using 'context'.
}
);

To make the code more readable, people use variables containing only underscores (_, __, …) to hint that they do not use their values:

return StreamBuilder(
stream: stream,
builder: (_, snapshot) { // Underscore for 'BuildContext context'
// ...
}
);

The problem is, the _ is still a real variable that can be used:

final themeData = Theme.of(_); // Underscore holds the BuildContext.

To address this mess, in future versions of Dart such variables will actually discard the value without the ability to read it. This means that the code above will stop working. To prevent that damage, the new no_wildcard_variable_uses lint was introduced. It flags all such instances that will later break.

implicit_reopen

According to the docs, this lint was available in Dart 3.0, but I could not find it on the page that I monitor for new lints back then and did not cover it in my article on lints of Dart 3.0, so here we go.

The interface keyword in Dart 3.0 allows to define a class (surprisingly, not necessarily an interface) that other libraries can only implement but not extend. This is useful to limit unwanted overrides that can inadvertently break the base class.

However, your “closed” class can be reopened if you extend it in your library without applying another “closing” modifier to it:

Use the new implicit_reopen lint to flag such occurrences that reopen classes you mean to close.

The Earlier Lints

If you have missed my articles on older lints, read them now:

Enabling the New Lints

Read this article on how to enable those new lints manually.

Alternatively, you can use my package total_lints which enables most of the lints for your project. I use it to avoid repeating the linter configuration for my projects.

--

--

Alexey Inkin
Flutter Senior

Google Developer Expert in Flutter. PHP, SQL, TS, Java, C++, professionally since 2003. Open for consulting & dev with my team. Telegram channel: @ainkin_com