In conjunction with the 2019 Google Developer Conference GDD in Shanghai,Dart Team announced the release of a stable version of the Dart 2.5 SDK, which includes a technical preview of two new developer features: ML Complete – Code completion driven by machine learning (ML), and dart: FFI external function interface for calling C code. Dart 2.5 also has improved support for constant expressions.

This release is a further refinement of the vision of realizing the best client optimization language for the rapid creation of applications for any platform. ML Complete is a powerful addition to the existing suite of productivity tools such as Hot Reload, Customizable Static Analysis, and Dart DevTools. The second preview, DART: FFI, enables you to leverage existing native apis on operating systems running Dart code, as well as existing cross-platform native libraries written in C.

Dart ranked 16th in this past week’s new IEEE Spectrum Top Programming Language 2019 ratings.

Preview :ML code completion

One of the core strengths of typed programming languages is that the additional information captured in types enables the IDE/editor to help developers by providing completion functionality when typing code. Developers can avoid spelling errors and explore the API by entering the beginning of the expected symbol and selecting from the provided completions.

As the API grows, exploration becomes difficult because the list of possible completions is too long to browse alphabetically. Over the past year, the Dart Team has been working to apply machine learning to this problem. Train models based on possible member events in a given context by analyzing a large amount of GitHub open source Dart code. The model is provided by TensorFlow Lite and can be used to predict the next symbol a developer is editing. Call this new feature ML Complete. Here is an example of developing a new MyHome widget using the Flutter framework:

How do I try ML Complete

ML Complete is built directly into the Dart analyzer and is therefore available in all DarT-enabled editors, including Android Studio, IntelliJ and VS Code. For more information on how to choose to use this preview feature, and for more information on how to provide feedback and report problems, see the Wiki.

Because this feature is still in preview, performance and optimizations that will be available in future releases of Flutter and Dart are not included in the current stable release. Therefore, it is recommended to temporarily use the Flutter Dev Channel or Dart Dev Channel when previewing this feature.

Preview: FFI external function interface for DART-C interoperability

Currently, calling C directly from Dart is limited to deep integration with the Dart VM using native extensions. Alternatively, A Flutter application can use C indirectly by calling the corresponding platform code using the platform channel and calling C forward from there. This is an unfriendly double call. The hope is to provide a new mechanism that provides excellent performance and runs on many supported Dart platforms and compilers.

Dart-c Interop supports two main scenarios:

  • Invoke c-based system apis on the operating system (OS)
  • Call c-based libraries, either on a single operating system or across platforms

Call the C-based operating system API

To call a Linux system command, the arguments passed to it are actually passed to shell/terminal and run there. The C header of this command:

// C header: int system(const char *command) in stdlib.h
Copy the code

The core challenge of any interoperability mechanism is dealing with semantic differences between the two languages. For DART: FFI, the Dart code needs to express two things:

  1. C The type of a function with its arguments and return types
  2. The corresponding Dart function and its type
// C header typedef:
typedef SystemC = ffi.Int32 Function(ffi.Pointer<Utf8> command);

// Dart header typedef:
typedef SystemDart = int Function(ffi.Pointer<Utf8> command);
Copy the code

Next, the function is called to encode the string parameters using the operating-system-specific encoding, and the parameter memory is freed again:

// Allocate a pointer to a Utf8 array containing our command.
final cmdP = Utf8.toUtf8('open http://dart.dev');

// Invoke the command.
systemP(cmdP);

// Free the pointer.
cmdP.free();
Copy the code

This code executes a system command that causes the system’s default browser to open dart.dev:

Invoke C-based frameworks and components

The second core use of DART: FFI is to invoke C-based frameworks and components. The ML-based code completion discussed in this article is a concrete example. It uses TensorFlow Lite, which is a C-based API. Using DART: FFI allows us to run TensorFlow on all operating systems that need to provide code completion, with the high performance of a native TensorFlow implementation. If you want to see the code for the Dart TensorFlow integration, look at this REPo.

Wrapping APIS and code generation

There is some programming overhead in describing functions and finding symbols. You can generate a lot of boilerplate code from C headers. So the current focus is on providing basic primitives for packaging.

How to try DART: FFI

Dart: FFI library preview released. Since it is still in preview state, it is recommended to use the Flutter Master Channel or Dart Dev Channel for quick access to the changes and improvements made.

Note that the API may change significantly between now and completion, as support for common patterns is added and expanded.

Here are some limitations to be aware of:

  • The library does not support nested structures, inline arrays, packaged data, or platform-specific primitive types.
  • Lack of Pointer operating performance (but you can use the Pointer. AsExternalTypedData to solve).
  • The library does not support finalizers (callbacks called when objects are about to be garbage collected).

The C Interop documentation and the DART: FFI API reference document document the core concepts.

Improved constant expression

Dart has long supported the creation of const constants and values; These are compile-time constants and therefore have very good performance characteristics. In previous versions, constant expressions were somewhat limited. Starting with Dart 2.5, more ways to define constant expressions are supported, including the ability to use casts and the new control flow and collection extensions provided in Dart 2.3:


// Example: these are now valid compile-time constants.
const Object i = 3;
const list = [i as int];
const set = {if (list is List<int>) ...list};
const map = {if (i is int) i: "int"};
Copy the code

Possible future features

The Dart Team is planning for Extension Methods, non-Nullable, and some early languages. Improved concurrency support is also being investigated – such as the ability to make better use of multi-core processors on modern phones.

The Dart Team has an ambitious plan for non-Nullable functionality and is doing a lot of work. Several recent new languages (such as Kotlin) were designed to support non-Nullable from the start, while most existing languages (such as Java) added non-Nullable support in later versions, which were limited to additional static analysis. In short, this means that the understanding of non-nullability extends to the heart of the type system, and once the type system knows something is non-nullable, it can trust that information completely, and the back-end compiler is free to optimize the code as it pleases. This robustness has great advantages in providing a consistent “exception-free experience,” as well as code size and runtime performance.