Today, we’re announcing that Dart 2.13 hasType the aliasThis is currently the second most requested language feature. Dart 2.13 also includes improvedDart FFIAnd better performance, and we’ve added new ones for DartDocker Official Images. This article provides the introduction in 2.12nullSecurity feature updates discussed in 2.13 about the new featuresDockerandGoogle CloudSome exciting news on support for the Dart back end, and a preview of some of the changes you might expect to see in future releases.

Air security update

We enabled sound invalidation security in Dart 2.12 in March. Null security is the latest major productivity feature in Dart and is designed to help you avoid null errors – a class of errors that are often hard to spot. With this release, we encourage package publishers to start migrating shared packages on pub.dev to security null. We were very pleased to see how quickly null security was adopted! Just a few months after its release, 93% of the 500 most popular packages on pub.dev already support NULL security. We’d like to thank all the package developers for getting this done so quickly and helping the entire ecosystem move forward! With so many packages that support NULL security, you’re likely to start migrating your applications to use NULL security. The first step is to use dart Pub outdated to check your application’s dependencies. For more information, see the Air Security Migration Guide. We also changed the Dart CREATE and Flutter Create templates so that null security is now enabled by default in new applications and packages.

Type the alias

Type aliasing is a new feature in the 2.13 language. It extends our previous support for creating type aliases for function types, but not for any other types. This highly sought after feature is the second highest rated feature in the Language Issues tracker. Using a type alias, you can create a new name for any existing type, which can then be used anywhere the original type can be used. You’re not actually defining a new type, just introducing a shorthand alias. Aliases even pass type equality tests:

typedef Integer = int;
void main() {
  print(int == Integer); // true
}
Copy the code

So what can you use a type alias for? A common use is to give a short or more descriptive name to a type to make your code more readable and maintainable. A good example is using JSON. Here, we can define a new type alias Json that describes the Json document as a mapping from the String key to any value (using the Dynamic type). Json can then use this type alias when defining the fromJson naming constructor and jsongetter

typedef Json = Map<String.dynamic>;
class User {
  final String name;
  final int age;
  User.fromJson(Json json) :
    name = json['name'],
    age = json['age'];
Json get json => {
    'name': name,
    'age': age,
  };
}
Copy the code

You can also call the constructor on the type alias of the named class, so the following is perfectly legal:

The main () {varJ = Json (); j ['name'] ='Michael'; 
}
Copy the code

Naming complex types using type aliases makes it easier for readers to understand code invariants. For example, the following code defines a type alias to describe a mapping List

containing a key of a generic type and the X value of type. By giving a type a name with a single type parameter, the mapped rule structure becomes more obvious to the code reader.

typedef MapToList<X> = Map<X, List<X>>;
void main() {
  MapToList<int> m = {};
  m[7] = [7]; // OK
  m[8] = [2.2.2]; // OK
  for (var x in m.keys) {
    print('$x --> ${m[x]}');
  }
}
=>
7 --> [7]
8 --> [2.2.2]
Copy the code

If you try to use a mismatched type, you will receive an analysis error:

m[42] = ['The'.'meaning'.'of'.'life'];
=>
The element type 'String' can't be assigned to the list type 'int'.
Copy the code

You can even use type aliases when renaming classes in a common library. Imagine PoorlyNamedClass and you want to rename an existing class in the public library to BetterNamedClass. If you just rename the class, your API customers will suddenly get a compilation error. With type aliases, you can continue renaming, but you can define a new type alias for the old class name, and then annotate the old name with @deprecated. When used, the PoorlyNamedClass is warned when used, but continues to compile and work as before, giving the user time to upgrade their code. PoorlyNamedClass (myLibrary.dart in a file named myLibrary.dart) :

class BetterNamedClass {... }@Deprecated('Use BetterNamedClass instead')
typedef PoorlyNamedClass = BetterNamedClass;
Copy the code

PoorlyNamedClass:

import 'mylibrary.dart';
voidmain() { PoorlyNamedClass p; } = >'PoorlyNamedClass' is deprecated and shouldn't be used. Use BetterNamedClass instead.
Copy the code

Starting with Dart 2.13, you can use the type alias feature. To enable it, set the lower Dart SDK constraint in Pubspec.yaml to at least 2.13:

environment:
  sdk: "> = 2.13.0 < 3.0.0"
Copy the code

This feature is backward compatible due to language versioning. Even if packages prior to 2.13 cannot define their own type aliases, packages with lower SDK constraints under 2.13 can safely reference type aliases defined in 2.13.

Dart 2.13 FFI changes

We also have some new functionality in Dart FFI, which is the interop mechanism we use to call C code. First, FFI now supports structures with inline arrays. Consider a C structure with an inline array, as follows:

struct MyStruct { 
  uint8_t arr [8]; 
}
Copy the code

Now you can wrap it directly in Dart and specify the element type Array using the type parameter:

class StructInlineArray extends Struct {
  @Array(8)
  external Array<Uint8> arr;
}
Copy the code

Second, FFI now supports packaging structures. Typically, structures are laid out in memory so that members are within address boundaries for easy CPU access. For packaged structures, some padding is usually omitted in a platform-specific manner to reduce overall memory consumption. Using the new @packed (

) annotation, you can easily specify padding. For example, the following code creates a structure with 4-byte alignment in memory:

@Packed(4)
class TASKDIALOGCONFIG extends Struct {
  @Uint32()
  external int cbSize;
  @IntPtr()
  external int hwndParent;
  @IntPtr()
  external int hInstance;
  @Uint32()
  external intdwFlags; . }Copy the code

Dart 2.13 performance changes

We are continuing our efforts to reduce the application size and memory footprint of the Dart code. In large Flutter applications, the internal structure of the metadata representing the AOT-compiled Dart program can take up considerable memory. Much of this metadata is provided to enable features such as hot reload, interactive debugging, and formatting of human-readable stack traces that are never used in deployed applications. Over the past year, we’ve been reorganizing the Dart native runtime to eliminate as much of this overhead as possible. Some of these improvements apply to all Flutter applications built in release mode, but some require you to discard human-readable stack traces by separating debugging information from aoT-compiled applications using the –split-debug-info flag.

Dart 2.13 contains a number of changes that significantly reduce the amount of space taken up by program metadata when –split-debug-info is used. Take the Flutter Gallery app for example. On Android, the APK released with debug information was 112.4MB and 106.7MB without debug information (a 5% decrease). This APK contains many assets. Just looking at the code metadata in APK, it was reduced from 5.7MB in Dart 2.12 to 3.7MB in Dart 2.13 (a 35% reduction).

If application size and memory footprint are important to you, consider using the –split-debug-info flag to omit debugging information. Note that in doing so, you will need to use the interest_command to make the stack trace readable again by humans.

Official Docker support and Dart on Google Cloud

Dart is now available as Docker Official Images. Although Dart has provided Docker images for many years, these new Dart images have been tested and validated by Docker to follow best practices. They also support ahead of time (AOT) compilation, which greatly reduces the size of built containers and can speed deployment in container environments such as Cloud Run. While Dart has been working to enable application frameworks like Flutter to drive beautiful pixels on every screen, we realize that most user experience is behind at least one hosted service. By using Dart to easily build back-end services, we enable a complete stack experience that allows developers to scale their applications to the cloud using the same language and business logic that supports the front-end widgets.

Dart for use with the Flutter application back end in general is particularly suited to the simplicity and scalability of the Google-hosted serverless platform Cloud Run. This includes a zero-to-zero ratio, which means you don’t incur fees when the back end is not processing any requests. Working with the Google Cloud team, we provide Dart with the Functions Framework, a set of software packages, tools, and examples that make it easy to write Dart Functions to deploy rather than using a full server to handle HTTP requests and CloudEvent. Check out our Google Cloud documentation to get started.

The follow-up plan

We’re already making some exciting changes for the upcoming release. As always, you can use Language Funnel to monitor our progress.

One area we are working on is a new set of specifications for Dart and Flutter. Lints is a powerful way to configure Dart static analysis, but with hundreds of possible LINTs that can be turned on or off, it can be difficult to decide what to choose. We are currently defining two standard linTs sets that we will apply to Dart and Flutter projects by default. We expect this to be enabled by default in the next stable release. If you need a preview, check out the lints and Flutter_lints packages. Finally, if you want to deeply embed the Dart VM runtime, be aware that we intend to deprecate existing mechanisms for this purpose. We’ll replace it with a faster, more flexible model based on THE Dart FFI.