Skip to main content

Dart 1.22: Faster tools, assert messages, covariant overrides

Dart 1.22 is now available. It introduces a sync/async union type, assert messages, covariant parameter overrides, and much more. Tool startup is now much faster. Get it now!

Faster tool startup

We have switched to using application snapshots for running our SDK tools like dart2js, analyzer, and pub. This improves startup performance. See the AOT compiling talk at Dart Dev Summit 2016 for more information. Information about how to use application snapshots can be found in the SDK wiki.

Here are the improved performance numbers we see with the switch.

Assert messages

The fail-fast principle is crucial for building high-quality software, and assert is the simplest way to fail fast. But until now, it wasn’t possible to attach messages to asserts, so if you wanted to make your error useful, you were forced to throw a full exception. Like this:

num measureDistance(List waypoints) {
  if (waypoints.any((point) => point.isInaccessible)) {
    throw new ArgumentError('At least one waypoint is inaccessible.');
  // ...

With messages in asserts, your code is not only shorter:

num measureDistance(List<Place> waypoints) {
  assert(waypoints.any((point) => point.isInaccessible),
         'At least one waypoint is inaccessible.');
  // ...

But, more importantly, asserts are completely skipped in production, so your production code will be faster (it won’t have to iterate over waypoints at the start of every measureDistance() call).

Covariant parameter override

In object-oriented class hierarchies, especially in user interface frameworks, it's fairly common to run into code like this:

class Widget {
  void addChild(Widget widget) {...}

class RadioButton extends Widget {
  void select() {...}

class RadioGroup extends Widget {
  void addChild(RadioButton button) {;

Here, a RadioGroup is a kind of widget. It refines the base Widget interface by stating that its children must be RadioButtons and cannot be any arbitrary widget. Note that the parameter type in RadioGroup.addChild() is RadioButton, which is a subclass of Widget.

This might seem innocuous at first, but it's actually statically unsound. Consider:

Widget widget = new RadioGroup(); // Upcast to Widget.
widget.addChild(new Widget());    // Add the wrong kind of child.

Tightening a parameter type, that is, using a proper subtype of the existing one in an overriding definition, breaks the Liskov substitution principle. A RadioGroup doesn't support everything that its superclass Widget does. Widget claims you can add any kind of widget to it as a child, but RadioGroup requires it to be a RadioButton.

Breaking substitutability is a little dubious, but in practice it works out fine. Developers can be careful and ensure that they only add the right kinds of children to their RadioGroups. However, because this isn't statically safe, many languages disallow it, including Dart strong mode. (Classic Dart permits it.)

Instead, users must currently manually tighten the type in the body of the method:

class RadioGroup extends Widget {
  void addChild(Widget widget) {
    var button = widget as RadioButton;;

The declaration is now statically safe, since it takes the same type as the superclass method. The call to select() is safe because it's guarded by an explicit as cast. That cast is checked and will fail at runtime if the passed widget isn't actually a RadioButton.

In most languages, this pattern is what you have to do. It has (at least) two problems. First, it's verbose. Many users intuitively expect to be able to define subclasses that refine the contracts of their superclasses, even though it's not strictly safe to do so. When they instead have to apply the above pattern, they are surprised, and find the resulting code ugly.

The other problem is that this pattern leads to a worse static typing user experience. Because the cast is now hidden inside the body of the method, a user of RadioGroup can no longer see the tightened type requirement at the API level.

Both problems are solved by covariant parameter overrides. To enable them on a method parameter, you mark it with the contextual keyword covariant:

class Widget {
  void addChild(covariant Widget widget) {...}

Doing so says "A subclass may override this parameter with a tighter desired type". A subclass can then override it like so:

class RadioGroup extends Widget {
  void addChild(RadioButton button) {
    // ...

No special marker is needed in the overriding definition. The presence of covariant in the superclass is enough. The parameter type in the base class method becomes the original type of the overridden parameter. The parameter type in the derived method is the desired type.

This approach fits well when a developer provides a library or framework where some parameter types were designed for getting tightened. For instance, the Widget hierarchy was designed like that.

In cases where the supertype authors did not foresee this need, it is still possible to tighten a parameter type by putting the covariant modifier on the overriding parameter declaration.

The covariant modifier can also be used on mutable fields. Doing so corresponds to marking the parameter in the implicitly generated setter for that field as covariant:

class Widget {
  covariant Widget child;

This is syntactic sugar for:

class Widget {
  Widget _child;
  Widget get child => _child;
  set child(covariant Widget value) { _child = value; }

Learn more about this feature in the changelog or in the informal spec.

The Null type is now a subtype of every other type

In other words, the Null type has been moved to the bottom of the type hierarchy. The null literal was always treated as a bottom type. Now the named class Null is too:

final empty = <Null>[];

String concatenate(List<String> parts) => parts.join();
int sum(List<int> numbers) => numbers.fold(0, (sum, n) => sum + n);

concatenate(empty); // OK.
sum(empty); // OK.


A lot of asynchronous code in Dart allows the use of a T or a Future<T>. For example, the callback to Future.then is declared to take a T but it doesn't specify the return type, since it could be an S or a Future<S>:

Future<S> then<S>(onValue(T value), { Function onError });

We are adding FutureOr<T> to support this use case. FutureOr<T> represents the union of Future<T> and T. So the signature of then now looks like this.

Future<S> then<S>(FutureOr<S> onValue(T value), { Function onError });

This tightens types in places where dynamic was used before (like with `then` above), and allows strong-mode tools to do better type inference. In non-strong-mode, FutureOr just means dynamic. In other places, where types were already tight but the implementation had to force asynchronous code, it will allow to loosen that requirement.

Generalized tear-offs are going away

Generalized tear-offs are no longer supported, and will cause errors. We updated the language spec and added warnings in 1.21, and are now taking the last step to fully de-support them. They were previously only supported in the VM, and there are almost no known uses of them in the wild.

Use of Function as a class is now deprecated

You can still use Function as a type name, but don’t use it as a class (don’t extend it, implement it, etc.). For example:

// This is deprecated.
class MyFunction extends Function {
  // …

But this is still okay

// This is okay.
void myAwesomeMethod(Function callback) {
  // …

Read the changelog for more information and additional changes.

This release took one additional week to finish (our regular schedule is a release each 6 weeks) but we think it was worth the wait.

Popular posts from this blog

Const, Static, Final, Oh my!

Posted by Seth Ladd

(This is an "oldie but a goodie" post originally written by Bob Nystrom. It is being posted here as the explanations still ring true.)

Bob writes:

"static", "final", and "const" mean entirely distinct things in Dart:

"static" means a member is available on the class itself instead of on instances of the class. That's all it means, and it isn't used for anything else. static modifies *members*.

"final" means single-assignment: a final variable or field *must* have an initializer. Once assigned a value, a final variable's value cannot be changed. final modifies *variables*.

"const" has a meaning that's a bit more complex and subtle in Dart. const modifies *values*. You can use it when creating collections, like const [1, 2, 3], and when constructing objects (instead of new) like const Point(2, 3). Here, const means that the object's entire deep state can be determ…

AngularDart 4

AngularDart v4 is now available. We've been busy since the release angular2 v3.1.0 in May. Not only did we "drop the 2", but we also improved the compiler and tightened up the framework to give you smaller code, we updated the package structure to improve usability, and we added several new features. Check out the updated documentation to get started.
Just angular Upgrading to v4 will require more than updating your version constraint. The package has changed names (back) to angular – dropping the 2. You'll need to update your pubspec.yaml and the corresponding imports in your code. In most instances, find-and-replace should do the trick. Going forward, the package will be called package:angular. We'll just update the version number.
Smaller code The updated compiler in 4.0 allows type-based optimizations that not only improve runtime performance but generate better code because we are able to strongly type templates. A big result of the update is that many ap…

The new AdWords UI uses Dart — we asked why

Google just announced a re-designed AdWords experience. In case you’re not familiar with AdWords: businesses use it to advertise on and partner websites. Advertising makes up majority of Google’s revenue, so when Google decides to completely redo the customer-facing front end to it, it’s a big deal. The Dart team is proud to say that this new front end is built with Dart and Angular 2. Whenever you asked us whether Google is ‘even using Dart for anything,’ this is what we had in mind but couldn’t say aloud. Until now. We asked Joshy Joseph, the primary technical lead on the project, some questions. Joshy is focusing on things like infrastructure, application latency and development velocity, so he’s the right person to ask about Dart.Q: What exactly did we launch on Monday?It’s a complete redesign of the AdWords customer experience that is rolling out slowly as a test to a small initial set of advertisers. The most noticeable thing is probably the Material Design look and f…