Announcement of beta testing null-safety Dart. Starting the process of migrating packages to a safe and secure state

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 announce that beta with robust null-safety available for Dart and Flutter. Null-safety is our latest major achievement, designed to help you avoid mistakes references to null values ​​are a class of errors that are often difficult to detect. This video explains in general terms the reason for our joy:

Coming to beta with null-safety it’s time to migrate thousands of packages available on pub.dev… We have ported the Dart core libraries, Flutter framework and more than 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 are looking forward to your feedback

Choosing null-safety

Before discussing migration to null-safety, we want to reiterate that (as stated in our null-safety principles) you have the ability to choose exactly when to start the transition. Apps and packages will only work with null-safety if their minimum Dart SDK limitation belongs to at least the pre-release version of Dart 2.12:

environment:
 sdk: ">=2.12.0-0 <3.0.0"

To try it out, try building a small null-safety hello app (for example, dart create) containing the code as shown below. Then you can try to run the app before and after changing the SDK limit and launch dart pub get and see how the behavior of the program changes. (Make sure that dart --version returns you exactly 2.12).

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 simple application) to null-safety mode, follow these five steps, which are detailed in migration guide at dart.dev.

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 migration, 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 before the pre-release versions listed in the column Resolvable

If null-safety support is available in newer minor versions, you will see them in the column Upgradable… Null-safety support will often be available in major new releases; in this case, you will see the versions listed under Resolvable in the output of the outdated utility. To go to them, edit the file pubspec.yamlto allow these major versions. For example, you can change
process: ^3.0.13 on process: ^4.0.0-nullsafety

Also you can find packages with null-safety support on pub.dev using new tags Null safety on package pages (e.g. collection 1.15) and a new option Advanced search null safety search.

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 is a summary of the best practices:

  • Update the version to the next major version (for example, from 2.3.x before 3.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 preview at pub.dev… (For example use 3.0.0-nullsafety.0, but not 3.0.0.)

For more information on migration and versioning, see migration guide

Benefits of guaranteed null-safety

In our previous posts on the null-safety technical preview in Dart and Flutter, a number of examples have discussed the benefits of these changes. Now that null-safety is nearing completion, we are seeing several real-world examples of this benefit.

More secure code

More recently we found a mistake in the main Flutter branch, which causes various tool commands flutter crashed 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. On null-safety static analysis immediately catches this problem:

This was a fairly simple mistake. 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:

  • An inner team found that they often checked for null values ​​in their code, which null-safety defined as never null. This problem most often occurs in code that uses protobufwhere optional fields return a default value when not specified and are never null. This caused the code to incorrectly check the default condition, mixing default and null values.
  • The Google Pay team found bugs in their Flutter code that prevented them from accessing Flutter objects State out of context Widget… Before null-safety, they returned null and masked the error; at null-safety, the analysis determined that these properties can never be null, and gave an analysis error.
  • The Flutter team encountered a bug that could potentially cause the Flutter engine to crash if null was passed to a parameter scene in Window.render()… During the migration to null-safety, they added a hint so that mark Scene as non-nullableand then were able to easily prevent potential application crashes that the passed null could cause.

Using robust null-safety at compile time

The null-safety of Dart is also important: Dart compilers can take advantage of null-safety information. It can make your programs smaller and faster. So far, we don’t 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 did a test recompilation of the sample hello_worldto measure the impact of null-safety on application size. This is a minimal example that just displays “hello world”. When comparison the 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 framework itself (package:flutter) decreased 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 the 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 revealed 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 a getter textAlignnon-nullable helped fix a caching error resulting in improved text rendering performance 14 times in cases of 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 Dart SDK archive

If you are developing packages, we recommend reading our migration guide and plan your migration. You are welcome, please let us know 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 want to listen to Michael’s report and communicate with him personally, come to DartUP 2020 Online December 4th and 5th and discuss the latest language updates with the Dart team and the community.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *