Dart emerged from Google a little after Go, and has recently surged in popularity as the language behind the Flutter cross platform front end framework. This matters to those interested in Cloud Native infrastructure, as there’s a push for ‘full stack Dart’ where Flutter developers can use the same language to build the services behind their apps. Dart’s support for ahead-of-time (AOT) compilation means that it can create lightweight binaries that start quickly, making it a good fit for Function-as-a-Service (FaaS) environments.
Flutter
Flutter is Google's UI toolkit for building beautiful, natively-compiled applications for mobile, web, desktop, and embedded devices from a single codebase.
Since Dart’s launch as “a new programming language for structured web programming” it has been targeted at front end developers, and it has found traction with the Flutter cross platform framework. Flutter 1 apps could be deployed to Android and iOS. With Flutter 2 apps can also be built for web and desktop. Canonical chose Flutter as the basis for the new Ubuntu Desktop installer. For The @ Company, where the author works, Dart was chosen for its Erlang-like features on the server side, along with the ability to build full stack apps with Flutter. Given the momentum behind Flutter, and its use by Google, it seems unlikely that there’s much risk of it joining the ‘killed by Google’ tombstones.
Flutter’s rising popularity, despite stiff competition from other frameworks like React Native, Xamarin, Ionic and Cordova, has pushed Dart to #20 in the RedMonk Programming Language Rankings: June 2021.
Last quarter we discussed Dart’s remarkable ascent after a long period of stagnation, an ascent almost certainly attributable to the popular Flutter framework, and asked the question as to whether Dart was done moving or if it had enough momentum to carry it into the Top 20. A quarter later, we have our answer, as Dart makes its Top 20 debut at #20 – displacing Perl in the process. This achievement in hand, the questions now are whether Dart can sustain a Top 20 ranking, and if so, whether it can continue moving up the charts.
Full stack Dart
The message emerging from Google at I/O 2021 was pretty much, “if you’ve learned Dart to write your Flutter app, why not also use it to implement the back end services on Google Cloud Platform”. They refer to this as, “full stack Dart”. At subsequent Flutter developer events such as Geekle 2021 representatives from AWS and Azure have shown up with a message that boils down to, “you can run Dart-based services on our clouds too”.
Language features
“Dart is a client-optimized language for fast apps on any platform”
— dart.dev
Dart is a strongly typed, garbage collected, object oriented language with C-like syntax. So it will look pretty familiar to anybody who’s worked with Java or C#, and many of the same patterns (and antipatterns) apply.
Hello World
void main() {
print('Hello, World!');
}
Just like with Java it’s easy to create objects that get used once then tossed away to await garbage collection:
Garbage antipattern
var args = ['parent-element', 'child-element']; # Create an object of arguments to pass
var value = getValue(args); # Create a result object and call function
if (value != null) { # Null test value of result object
return value; # Return result object
}
The async/await model that will be familiar to many JavaScript programmers is used to support asynchronous programming, which is particularly useful for event-based applications
Asynchronous functions example
Future<String> createOrderMessage() async {
var order = await fetchUserOrder();
return 'Your order is: $order';
}
Future<String> fetchUserOrder() =>
// Imagine that this function is
// more complex and slow.
Future.delayed(
const Duration(seconds: 2),
() => 'Large Latte',
);
Future<void> main() async {
print('Fetching user order...');
print(await createOrderMessage());
}
Concurrency is achieved using isolates - “independent workers that are similar to threads but don’t share memory, communicating only through messages”, except when deploying to the browser, when HTML5 Web workers should be used instead. This aspect of the language is reminiscent of Erlang processes, and it’s straightforward to implement an actor model.
The language and core packages are licensed with the 3-Clause BSD License, and many third party packages also use that license.
pub.dev package manager
Dart’s package manager is pub.dev, and an application’s dependencies are defined in a pubspec.yaml file that can reference published packages and packages in Git URLs. Anybody with a Google account can publish packages, however the site supports a concept of DNS-based verified publishers to provide some degree of provenance for packages. Packages are also scored using ‘pub points’ based on adherence to file conventions, documentation, multi-platform support, passing static analysis, whether dependencies are up to date, and if sound null safety is supported.
The pub.dev public API has endpoints to list the top packages for package name completion in IDEs, and to list all versions of a package.
Just in time and ahead of time compilation
When running apps in the Dart virtual machine (VM), it supports just-in-time (JIT) compilation similar to other VM-based languages. This creates the usual trade off between start up time, and long term efficiency where the VM has been able to optimise running code. The Dart VM includes a profiler, originally known as ‘Observatory’, which can be used with the DevTools debugging and performance suite.
The alternative to JIT is ahead-of-time (AOT) compilation, where the Dart SDK creates a native binary for Arm, Arm64, x86 or x64, or JavaScript for apps being deployed to the browser. AOT binaries have very short startup times, which makes them a good fit for ‘serverless’ environments such as Function-as-a-Service (FaaS).
However there aren’t currently any FaaS platforms that support Dart natively, which means that apps have to be packaged into containers and run on the variety of platforms that support containerised apps. Google has created the Functions Framework for Dart to provide some scaffolding for building FaaS. The framework is designed to run locally, and on Google Cloud Run, Google App Engine, and Knative-based environments. It includes a full stack example that runs a Dart service at the back end used by a Flutter desktop/web application at the front end.
Dart on Docker
An official Dart image has been available on Docker Hub since May 2021, which includes the Dart SDK in a debian:buster-slim image.
Dart is a dynamically linked language, so unlike Go, it’s not possible to create a statically linked binary that can be placed in a ‘FROM scratch’ empty container. To get similarly small containers the Dart image includes a /runtime directory that contains a minimal working set of platform libraries. A trivial ‘Hello World’ type application fits into 3.5-4.5MB depending on the underlying platform architecture.
FROM dart AS build
WORKDIR /app
COPY ./mydemoapp.dart .
RUN dart pub get
RUN dart compile exe /app/mydemoapp.dart -o /app/mydemoapp
FROM scratch
COPY --from=build /runtime/ /
COPY --from=build /app/mydemoapp /app/mydemoapp
ENTRYPOINT ["/app/mydemoapp"]
Multi-platform and architecture support
The Dart SDK is available for development on Windows (x86 and x64), Linux (x86, x64, Arm and Arm64) and MacOS (x64 and Arm64). The SDK can create native binaries for the platform it’s running on, but doesn’t presently support cross compilation. So creating multi-architecture binaries requires multi-architecture build infrastructure, or the use of emulation (such as QEMU with Docker Buildx).
The official Dart image only supports linux:amd64, with Arm/Arm64 support coming from community forks.
Flutter does support cross compilation, so native binaries for Android, native binaries for various desktops, and web applications can all be built and tested from any of the supported platforms (though a Mac and Xcode is still needed to build and release an iOS app).
New features
Dart is very much in active development, with new features arriving to make the language faster, more secure, and more flexible.
Sound null safety
Released with Dart 2.12 (alongside Flutter 2) in March 2021, sound null safety means that types are non-nullable by default. This means that null-dereference errors that would crop up at runtime. can be identified during the editing and compilation process. It’s still possible to declare nullable variables by appending a ? to the type declaration, so developers have control over how they make use of the feature.
// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
// To indicate that a variable might have the value null
// just add ? to its type declaration
int? aNullableInt = null;
Introducing sound null safety has been viewed as a breaking change for packages in pub.dev, with Google advising that major version numbers should be bumped for null safety compatible releases. After a few months most of the popular packages (and their underlying dependencies) have adopted sound null safety, showing that the ecosystem is active and able to embrace changes.
Web Assembly
Experiments are underway for Dart to be able to compile into Web Assembly (WASM) modules, which are somewhat reliant on WebAssemby/gc to provide better support for garbage collected languages.
Dart can also make use of WASM modules via the :wasm package, which is based on Wasmer runtime. This opens the door to Dart apps using libraries from C, C++, Rust etc. in a platform independent way (which should be a lot more flexible than C interop provided by the foreign function interface [ffi]).
If you are unfamiliar with Web Assembly, you might want to read Kevin Hoffman’s mini-series of articles (one, two) on WTF which provide a good concise overview.
IDEs
Dart and Flutter have a number of decent options in terms of the available developer tooling. The get started guide for Flutter directs users towards Android Studio, which is based on JetBrain’s IntelliJ IDEA.
Dart and Flutter also have good support in VS Code by using the Dart Code extension.
Alternatively, apps can be edited and tested in the browser using DartPad, which is used extensively for the Dart tutorials.
Rough edges
As we’ve seen, Dart has a wide range of capabilities. However there are also some frustrations:
YAML
YAML is used extensively by Dart, not least for defining dependencies in a pubspec.yaml file. The YAML parser is a package on pub.dev that comes with this disappointing statement:
This library currently doesn't support dumping to YAML. You should use json.encode from dart:convert instead.
Just parsing YAML is generally fine for most client apps. But not being able to dump YAML (with v1.2 support and round tripping) is a nuisance for server side apps and command line utilities, and often means that Python scripts or similar need to be brought into Dart build pipelines because a pure Dart approach can’t be used.
TLS
Dart supports TLS 1.0 and 1.1, which are now deprecated, but there isn’t yet a means to specify 1.2 as the minimum version, leaving apps open to downgrade attacks. There are a variety of issues open on the SDK repo seeking to address this, with #37173 recently noting: “it's P1 with an internal customer”.
Release notifications
The Dart SDK Archive page carries the latest release numbers for the various channels (Stable, Beta and Dev), but there’s no easy way (such as an RSS feed) to subscribe to updates. The Dart Announcements Google Group only carries minor releases for Stable (not patches), whilst the SDK releases page on GitHub is too noisy with dev releases. Perhaps the best source is versions.json in the dart-docker repo.
Community
The Dart language community exists as a subset of the larger Flutter community, which spans both the usual selection of online meeting places and the physical world through a variety of events (as things return to being in-person).
Dart and Flutter are two separate categories for Google Developers Experts (GDEs), though in practice there’s enormous overlap between them.
If you’d like to try Dart
The best place to start is the Dart Tutorials page, which has sections on the basics, server-side Dart, and web apps. Many of the tutorials make use of Dart Pad so that sample code can be edited and run in a browser, meaning there’s no need to install anything to get started.