null Safety in Dart

Two days ago the Dart team announced the preview release of their null safety framework. So why would we want it? What is it? How can we use it?

Why Should we care about null safety?

You don’t have to deploy many projects before you begin to learn that users find weird and interesting ways to use your apps. Ways you never considered or intended! The functions and methods you wrote, and tested, that couldn’t possibly fail, fail in a big way. Bug reports roll in containing error messages that methods were called on null objects or an attempt was made to convert a null value to String. Where did these errors come from? How did an object or value become null?

A search for errors will reveal that null errors are one of the most common causes of application failure. During development we often fail to see that the result of an operation may return null. As our applications become more complex, we fail to see code paths that could result in a variable not being created or instantiated, or a value that may never be set. By default these values will be null. given a 100 line or even a 500 line program we may be able to reason about all code paths and all object instantiations and values. However, when writing most applications today not only are we writing our own code but, we are building on top of tens or even hundreds of thousands of lines of code that was used to build the libraries, frameworks, and tools we use daily. Any one of these lines we don’t even see can contain hidden errors and failure paths that can bring our apps down. Additionally, we can rarely write only a couple hundred lines of code and have a deployable app. Most apps require far more lines of code. As the size and complexity of our code base grows our ability to hold a complete picture of it in our heads diminishes exponentially! If you think you can understand and reason about every line in a 1000 line program, a 10,000 line program becomes 100 times harder to reason about!

So, being human as we are, we all fail to see even the most simple possible failures. Often we expect that the underlying code will catch errors for us and mentally pass the buck as we push forward to meet our deadlines. Even if we practice TDD (Test Driven Development), we still have some preconceived notions about our code and the code we are building upon. It is this inability to reason about each line of code and it’s full-effects in every possible situation that leads us down the dark road of many a midnight debugging session.

As an exercise, try and spot the issue with the code below:

void printPersons(List<Person> persons) {
  for (var person in persons) {
    print(person.name);
  }
}

Can you spot the errors? Perhaps you see that the printPersons() function can be called with a null list value. But the list could also be created with a null person entry. Either of these events would cause the function to fail.

But these errors have other costs besides our own annoyances and manpower costs. They decrease market share by annoying the user. Which in-turn decreases profits and if allowed to go unchecked, they can build a mental picture of a company or developer who creates crappy products thereby destroying future profits and production.

Dart code with null safety error.

Error reported by non-nullable age being set to null.

What is a null safety framework?

A null Safety framework is a toolset for recognizing, locating, and correcting issues that could result in null value errors. With null safety, we can more easily reason about our code. Instead, the framework will generate static errors at compile-time.

Sound null Safety

Dart can be 100% sure that the persons list, and it’s elements cannot be null in the example above. When dart inspects the code it is compiling, and determines that a variable is non-nullable, that variable is always non-nullable. The variable remains non-nullable even at runtime. This makes dart’s nul safety “Sound” as compared to some language implementations.

Dart’s null safety soundness has other implications for our code: For example, it means that our programs can be smaller and faster because dart can be sure that non-nullable variables are never never null. This alleviates the need for null checks compiled into the release code.

How can we use it?

Way back in October of 2011 Bob Nystrom posted on his blog about the null safety issue. He outlined a non-official set of guidelines for the syntax and semantics of null safety in the dart language. It looks like the dart team finally got around to implementing his suggestions. Though I haven’t dug into the details, cursory review leads me to believe that much of what has been implemented began with Bob’s post. If this is true, then the following guidelines should help us use the new null safety features:

As defined by Bob: By default, all types are non-nullable. If you declare a variable of type int, it is a static error to try to assign null to it. In checked mode, it is a dynamic error to assign null to a non-nullable variable.

You can define a nullable type by adding ? after the type name. int is non-nullable, int? is nullable. Non-null types are a property of Dart’s type system, but (unlike Maybe or option in other languages) not a part of its runtime behavior.

At runtime, Dart continues to work like a dynamic language where any variable may hold a value of any type, including null. “Nullability” is as optional as the rest of Dart’s type system.

Conclusion

null Safety is the latest feature being added to Dart 2.x. It should prove to be a valuable feature in reducing errors at runtime. Like all features there is a trade-off. Since by default all variables are non-nullable, current code will need to be modified to deal with this. After all, there are legitimate uses for setting a variable to null and those will require some source modifications.

In the long-run however, I expect that dart’s null safety will make us more productive as developers and our application must more robust.

Do note that null safety is still not production-ready. You can test it out on a special version of dart pad. However, it will soon be coming to an IDE near you! When it does, dig in and begin using it. Report back how it’s features and implementation affect your code, production, and implementations.

As always, Happy Coding!

Leave a Reply

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