Of course, null-safety is an important step in the development of the language. The Dart team has announced a beta release of the null-safety version! We have translated into Russian the news about this release, in which you will learn how to migrate to new versions, what benefits you will get, and what is the benefit of null-safety for all of us.
Today we are announcing that a reliable null-safety beta is available for Dart and Flutter. Null-safety is our latest major advance to help you avoid null-referencing bugs, a class of bugs that are often difficult to detect. This video explains in general terms the reason for our joy:
With the move to the null-safety beta, it's time to migrate the thousands of packages available on pub.dev . We've ported the Dart core libraries, Flutter framework, and over 40 Dart and Flutter packages. That being said, we hope that the community will accept null-safety by migrating their packages.
With the beta release, we are also entering the home stretch before the null-safety stable release is released. We hope you take advantage of this functionality and let us know if we can improve it and make the UI messages and documentation clearer. We look forward to your feedback .
Choosing null-safety
Before discussing migration to null-safety, we want to reiterate that (as stated in our null-safety guidelines ) you have the ability to choose exactly when to start the migration. Apps and packages will only work with null-safety if their minimum Dart SDK limit is at least the pre-release version of Dart 2.12:
environment:
sdk: ">=2.12.0-0 <3.0.0"
To try it out, try creating a small null-safety hello app (for example with
dart create
) containing the code as shown below. You can then try running the application before and after changing the SDK limit and launch dart pub get
and see how the program's behavior changes. (Make sure to dart --version
return exactly 2.12 to you).
bin/hello.dart:
...
void main() {
var hello = 'Hello Dart developers';
if (someCondition) {
hello = null;
}
print(hello);
}
Before changing the SDK constraint:
$ dart run
null
After changing the SDK constraint (and running dart pub get):
$ dart run
bin/hello.dart:6:13: Error: Null can't be assigned to a variable of
type 'String' because 'String' is not nullable.
hello = null;
^
Moving to null-safety
To migrate a package (or a simple application) to null-safety mode, follow these five steps, which are detailed in the dart.dev migration guide.
Step 1: check if your dependencies are ready
We strongly recommend that you move the code in order, starting with the "leaves" of the dependency graph. For example, if C depends on B, which depends on A, migrate first to null-safety A, then B, then C. This order applies whether A, B, and C are libraries, packages, or applications.
Why is order so important? You can make some progress in migrating your code before migrating your dependencies, but you run the risk of having to rerun if your dependencies change their interfaces during the migration. If some of your dependencies are not null-safety, consider contacting the package publishers using the contact details listed for each package on pub.dev.
Checking if dependencies are ready
To check if your application or package is ready to start migrating, you can run
dart pub outdated
in null-safety mode. The example below shows that the application will be ready to migrate if it updates its dependencies to path
, process
and pedantic
to, the pre-release versions listed in the Resolvable column .
If null-safety support is available in newer minor versions, you will see them in the Upgradable column . Null-safety support will often be available in major new releases; in this case, you will see the versions listed in the Resolvable section in the output of the outdated utility. To switch to them, edit the file
pubspec.yaml
to allow these major versions. For example, you can change
process: ^3.0.13
to process: ^4.0.0-nullsafety
.
You can also find packages with null-safety support on pub.dev using the new Null safety tags on package pages (e.g. collection 1.15 ) and the new Advanced null safety search option .
Step 2: transfer using the migration tool
Once the dependencies are ready, you can start migrating your application or package using the migration tool
dart migrate
.
The migration tool is interactive, so you can view the null-safety properties inferred by this tool. If you disagree with any result of the tool, you can add null hints to change it. Adding just a few hints can have a huge impact on the quality of your migration.
Several Dart package authors have tested migrations using early pre-build null-safety builds, and their feedback has been encouraging. The migration guide has additional tips for using the migration tool.
Step 3: static analysis of the ported code
Update packages using pub get in your IDE or command line. Then use an IDE or command line to perform static analysis on your Dart code:
$ dart pub get
$ dart analyze
Or in Flutter code:
$ flutter pub get
$ flutter analyze
Step 4: make sure the tests pass
Run tests and make sure they pass safely. You may need to update tests expecting null if you change your package code to not allow null values.
Step 5: publish your null-safety package
After completing the migration and running the tests, you can publish your package as a Prerelease. Here's a summary of the best practices:
- Upgrade the version to the next major version (for example, from
2.3.x
to3.0.0
). This ensures that users of your package don't upgrade to it until they're ready to use null-safety. This gives you the freedom to refactor your API to make the best use of null-safety. - Translate and publish your package as a preview at pub.dev . (For example, use
3.0.0-nullsafety.0
rather than3.0.0
.)
For more information on migration and versioning, see the migration guide .
Benefits of guaranteed null-safety
Our previous posts on null-safety technical previews in Dart and Flutter discussed the benefits of these changes using a number of examples. Now that null-safety is nearing completion, we are seeing several real-world examples of this benefit.
More secure code
We recently discovered a bug on the main Flutter branch that caused various tool commands to
flutter
crash on certain machine configurations with a null: error The method '>=' was called on null
. The main issue was a recent pull request to add support for Android Studio 4.1 detection. This pull request added code like this:
final int major = version?.major;
final int minor = version?.minor;
if (globals.platform.isMacOS) {
/// plugin path of Android Studio changed after version 4.1.
if (major >= 4 && minor >= 1) {
...
Can you find a bug? Since the version can be null, both the major and minor versions can be null as well. This bug may seem easy to find here in isolation, but in practice this kind of code slips through all the time, even with the rigorous code review process used in the Flutter repository. With null-safety, static analysis catches this problem immediately :
It was a fairly simple error. In the early days of using null-safety in Google's internal code, we saw how much more complex errors were detected and then resolved by null-safety. Here are some examples:
- , null , null-safety null. , protobuf, , , null. , , - null .
- Google Pay Flutter, - Flutter
State
Widget
. null-safety null ; null-safety , null, . - Flutter , - Flutter , null
scene
Window.render()
. null-safety , Scene , , null.
null-safety
Dart's null-safety reliability is also important: Dart compilers can take advantage of null-safety information. It can make your programs smaller and faster. So far, we do not have many real applications fully translated to null-safety (after all, we are just now starting to migrate the ecosystem of packages that these applications depend on for reliability), but we are seeing very encouraging results from the main framework.
We recently ran a test recompilation of the hello_world sample to measure the impact of null-safety on application size. This is a minimal example that just displays "hello world". When comparingthe total size of the compiled code, the size of the uncompressed (installed on the device) code was reduced by 3.5% without any action other than recompilation with reliable null-safety. This was possible despite the fact that the entire application consisted of 10 lines of code, because the code size of all included libraries was reduced; for example, the Flutter (
package:flutter
) framework itself has shrunk by 3.9%.
In terms of code speed, having to enforce a trusted data type system potentially increases overhead. However, fewer null checks also potentially speed up your code. Initial analysis of benchmarks shows that performance is on par with previous releases, and new additional type information gives us the potential for new ways to improve performance in the future. We plan to write more about this in future publications.
In some cases, we've already seen how null-safety led to performance gains when the transition found a flaw in the code's logic. For example, we found an issue in the Flutter web's text positioning cache. This cache used a nullable key and then, according to the given logic, used
TextAlign.start
when null. This logic threw a cache error where items looked like they had changed, even though they still had a default value. As a result, there were often unproductive calls to the cache. Adding getter textAlign
that does not allow null, it is helped to correct the error caching, resulting in increased rendering performance of the text 14 times in cases cached text.
Get started today!
The beta versions of Dart and Flutter containing null-safety are ready. If you are writing in Flutter, you can switch to beta with
flutter channel beta
and then flutter upgrade
. And if you're not using Flutter, you can get the standalone Dart SDK from the Dart SDK archive .
If you are developing packages, we recommend reading our migration guide and planning your migration. Please let us know about any problems or suggestions you have.
If you're an app developer, you can postpone the port until the feature arrives in our stable releases. We plan to quickly respond to beta feedback and fix any remaining issues. It is difficult to give a specific timeline for when null-safety will be released in a stable release, but we are thinking about early next year.
Thanks for your support and feedback! We are working to make Dart a more robust language and Flutter a more powerful framework.
Michael Thomsen, Product Manager for Dart and Flutter, posted this article on the official Dartlang Blog. If you'd like to listen to Michael's talk and interact with him in person, come to DartUP 2020 Online on December 4th and 5th and discuss the latest language updates with the Dart team and the community.