The power of Null Safety in Dart

author image
Tigran Muradyan
Tags
  • #DART
  • #NULL-SAFETY
  • #LIONIX
  • #FLUTTER
  • #APPS
The power of Null Safety in Dart

To start, as we know, the development of the mobile app, web, or other software has many challenges and obstacles named errors. All programming languages, such as Dart, have various helpful tools to avoid these breaking points and fasten the coding process. Let’s guess the name of such a tool by simply looking at the title of the article. Yes, you are right; the name of the powerful tool, which was released with Dart 2.12, is “Sound null safety.”

Above all, let’s take a minute and talk about the meaning of the word “null-safety.”

Void safety (also known as null safety) guarantees an OOP (object-oriented programming) that no object references will have null or void values. To gain more information about null type values, read this.

Well, Null safety is the latest prominent productivity feature, intended to help developers avoid null errors, a class of bugs that are often hard to spot, as detailed in the following video introduction.

Before we look at sound null safety and detail, let’s discuss how they fit into the Dart platform’s goals. As we mentioned above, programming languages tend to share many capabilities that make developers’ lives easier. Sound null safety makes the type system even more robust, helps avoid unexpected errors related to invalid values, and enables better performance.

How is it done? Feature strengthens the type system, allowing the developer to catch null mistakes, which cause app crashes. You can detect null errors during development by opting into null safety, preventing crashes in production — no more errors like this:

In other words, Null safety isn’t just about safety. We also want you to be productive when using the feature, which means that the feature must be easy to use.

Now, when we have already defined the meaning of null safety and its advantages, let’s dive into core Null safety principles.

Dart null safety support is based on the following three core design principles:

  1. Non-nullable by default. Unless you explicitly tell Dart that a variable can be null, it will be considered non-nullable. We chose this as the default because we found that non-null was the most common choice in APIs.2.
  2. Incrementally adoptable. There’s a lot of Dart code out there. It will be possible to migrate to null safety when you choose to, and then incrementally, part by part. It will be possible to have null-safe and non-null-safe codes in the same project. We’ll also provide tools to help you with the migration.
  3. Fully sound. Dart’s null safety is sound. This means that we can trust the type system: if it determines that something isn’t null, it can never be null. This enables compiler optimizations. Once you migrate your whole project and your dependencies to null safety, you reap the full benefits of soundness — not only fewer bugs but smaller binaries and faster execution.

Non-nullable by default

First and foremost, variables are non-nullable by default. Dart will make sure that you never assign null to any of the above variables. If you try to do, for example, widget = null a thousand lines later, you’ll get a static analysis error and red squiggly lines, and your program will refuse to compile. If you want your variable to be nullable, you can use “?” like this:

Although, once again, the dream is that devs rarely have to use “?”. The majority of types will be non-nullable.

Incrementally adoptable

Because null safety is such a fundamental change to Dart’s typing system, it would be highly disruptive if they insisted on forced adoption. They let us decide when the time is right, so null safety is an opt-in feature: we will be able to use the latest Dart and Flutter releases without being forced to enable null safety before ready to do so. We, developers, can even depend on packages that have already enabled null safety from an app or package that hasn’t yet. Overall, sounds good, yeah?

Hence, when dependencies are ready, we can use the migration tool. The tool works by analyzing all of the existing code. The migration tool is interactive, so we can review the nullability properties that the instrument has inferred. If we disagree with any of the tool’s conclusions, we can add nullability hints to change the inference.

So, adding a few migration hints can have a significant impact on migration quality.

Fully sound

Once we’ve fully migrated, Dart’s null safety is sound. This means that Dart is 100% sure that the return variables, lists, and elements cannot be null in the above examples. When Dart analyzes the code and determines that a variable is non-nullable, that variable is always non- nullable. If we inspect running code in the debugger, we’ll see that non-nullability is retained at runtime. By contrast, some other implementations are unsound, and in many cases, still, need to perform runtime null checks. Also, Dart shares sound null safety with Swift, but not very many other programming languages.

Dart’s null safety soundness has another welcome implication: it means programs can be smaller and faster. Because Dart is sure that non-nullable variables are never null, Dart can optimize. For example, the Dart ahead-of-time (AOT) compiler can produce smaller and faster native code because it doesn’t need to add checks for nulls when it knows that a variable isn’t null.

Finally, let’s start experimenting with null safety today! To get prepared quickly, check out this particular version of DartPad with null safety.