Today, we’re announcing the stable release of Dart 2.1, an update to Dart 2 that offers smaller code size, faster type checks, better usability for type errors, and new language features to improve productivity when building user experiences.
As part of the transition to Dart 2, we added a sound type system to support large teams building complex apps, new compiler support for generating native code optimized for mobile devices, and completely reworked web platform tools. Dart powers Flutter, our fast-growing toolkit for building beautiful native experiences for iOS and Android from a single code base; it is also the language used by some of the largest projects at Google, such as Google Ads.
Since the launch of Dart 2 back in August, we’ve worked on getting the whole ecosystem onto Dart 2. We switched our dartlang.org website over to use Dart 2 examples everywhere, and we offered tools and documentation for migrating Dart 1.x packages. We understand that the large changes in Dart 2 involved migration work for existing Dart developers, and we’re very thankful to those who have helped us build a new foundation for the future. Our focus now shifts to taking advantage of these investments to deliver improvements to performance and productivity.
New Flutter developers are often tripped up by analysis errors like these when specifying padding, setting font sizes, etc.:
From a system point of view, these errors make sense: The API expects one type (a double), and the developer specifies a value of a different type (an int). However, from a usability point of view it seems a bit foolish: There is a trivial conversion from int to double, so why not just do that? Dart 2.1 now infers where an int can be silently evaluated as a double:
We also improved Dart’s support for mixins. If you haven’t encountered Dart mixins before, it’s worth reading this great introduction to Dart mixins by Romain Rastel. Dart 2.1 introduces a new syntax for mixins, featuring a new
mixin keyword that you can use to define classes that can only be used as mixins. We’ve also added support so that mixins can extend other classes (previously they could only extend
Object) and can invoke methods in their superclass.
One example of extending non-Object classes is from Flutter’s animation APIs, where the
SingleTickerProviderStateMixin — a framework class that provides a ticker for advancing an animation by a single frame — declares a mixin that implements the general TickerProvider interface. Animations are only applicable to stateful widgets (as the position in the animation is considered state). The new mixin support allows us to express this by declaring that only classes that extend the Flutter State class can use the mixin:
Dart 2’s sound type system protects you during development, telling you when you violate the contract specified by the types. For example, let’s say you’re creating a state class for Flutter. This class is expected to extend the framework
State class. A
State class expects to be passed the
StatefulWidget that it contains the state for.
Now, should you make a programming mistake and — say — pass it a descendant of
StatelessWidget instead of
StatefulWidget, the type information enables the tools to catch the mistake and show you a warning immediately:
These edit-time type checks were added in Dart 2.0 (powered by the Dart Analyzer). However, there is another place where you might expect these type checks, namely at compile time, when you do a Flutter release build. These checks were incomplete in Dart 2.0, which could lead to usability issues where bad source code could compile without producing any errors. In Dart 2.1, these checks are complete, and the Analyzer and Dart compiler contain the same checks.
Dart 2 was generally faster than Dart 1.x for AOT-compiled code running on our VM, such as Flutter apps. In a few edge cases, though, the comprehensive checks added by the new type system caused an undesirable overhead of 20–40%. In Dart 2.1 we’ve greatly reduced the cost of the type checks, both for AOT-compiled code and for code run in the VM with JIT (just-in-time) compilation.
One concrete case that benefits from this is our developer tools (which run using the VM). For example, performing code analysis of one large benchmark app (based on multiple concatenated copies of the Flutter Gallery) used to take ~41 seconds; now it takes ~25 seconds.
We also improved the code size and compile time for Dart code running on the web. We focused on the output size of dart2js and are seeing good results, such as a 17% reduction in minified output size and 15% improvement in compilation time for one of our samples.
In addition to the above-mentioned changes in the Dart SDK, we’ve made some exciting changes outside of the core SDK.
Protocol buffers (or protobuf for short) are a platform-neutral mechanism for serializing structured data. They’re used extensively inside of Google and are also seeing strong adoption outside of Google — for example as part of gRPC. Dart is now an officially supported protobuf language, and we have added detailed documentation on the core protocol buffers website with both a tutorial and reference documentation.
You may have heard about knative — a platform based on Kubernetes — to support building, deploying, and managing serverless workloads. We recently investigated support for serving Dart code on knative, and created a small sample. This is likely too low-level for most Dart app developers, but we find it very exciting from a platform perspective, and anticipate this will be a critical building block to get better support for serving Dart code in the Google Cloud — for example to create backends for Flutter apps.
Dart SDK 2.1 is available from the Dart homepage. If you’re a Flutter developer, Dart 2.1 is included as part of the upcoming Flutter 1.0 release.
We expect to ship several 2.x releases that take advantage of the Dart 2 platform foundation. We’ll base these on the needs of our framework partners and app developers. In 2019 we expect to investigate the following areas:
- Continued evolution of the Dart language: For Dart 2.2, we’re investigating a number of changes, such as refinements to const expressions and support for a new Set literal. Beyond 2.2 we’re looking into our support for Unicode strings, and are investigating whether we can offer better null safety.
- Further improvements to optimize Dart as a language for creating user interfaces: Dart 2 began this journey with its new type system and optional new, Dart 2.1 added int to double value inference, and we are currently investigating a number of potential improvements such as support for conditionals in widget lists, expanding collections of objects into other collections, and even potentially removing the need to terminate statements with semicolons.
- Even better performance: We’ll continue to reduce the size and performance of compiled Dart code, including better support for using multi-core processors, further reduction of code size to improve download and startup time, and potentially more control for whether size or runtime performance is most critical.
For more about both Dart and Flutter, we’d love you to join us at Flutter Live, an online event taking place on December 4th that will be streamed live on the web. We’re excited to share more about the roadmap with you then.
That’s it for now. We hope you enjoy Dart 2.1!