A Student's Guide to Software Engineering Tools & Techniques »

Introduction to Dart

Author: Tan Yuanhong

Reviewers: Daryl Tan, Ang Ze Yu, Tejas Bhuwania

What is Dart?

Dart (previously also known as dartlang) is an object-oriented, a style of Object-oriented programming (OOP) in which inheritance occurs via defining classes of objects, instead of inheritance occurring via the objects alone (compare prototype-based programming)class defined, garbage-collected language using a C-style syntax that also known as source-to-source compilationtranscompiles optionally into JavaScript. It's rumored that Dart was invented out of Google engineers' frustration with JavaScript (they even built a version of Chromium browser with Dart VM so that Dart code can be run on the web without transcompiling to JavaScript). However, as most developers still stick to JavaScript and it turned out that TypeScript is a much more widely-accepted solution for statically typed JavaScript transcompilation, Dart is then, with the emergence of a cross-platform mobile UI framework developed by GoogleFlutter, re-purposed as a client-optimized language that's optimized for UI creation and cross-platform execution.

Why Learn Dart?

Optimized for Declarative UI

Dart is optimized for declarative UI. Dart's syntax allows you to write statically typed code in a JSON-like way, and writing asynchronous code is a breeze in Dart, both of which makes Dart an ideal choice for developing declarative UI.

For the reasons above, Dart is adopted by Flutter, a cross-platform mobile UI framework. (Why Flutter?) Not only you shall build Flutter apps using Dart, the Flutter framework itself is written in platform-dependent channel methods excluded, of course...pure Dart. In short, Dart is suitable for writing declarative UI, and Dart is a pre-requisite for Flutter.

Fast Development and Native Performance

A programming language usually needs to balance between development speed and performance. Dart is ambitious: it wants to run fast on all platforms (which requires compilation to native machine code) while allowing the developers to live reload code changes without re-compiling the entire file (which requires a VM of some kind). Thus, Dart has three execution modes for the best of all words:

  • for fast development, Just-in-timeJIT + Dart VM;
  • for native performance: Ahead-of-timeAOT compilation to platform-specific instructions;
  • for browser support: source-to-source compiler to JavaScript

The flexibility provided by the three execution modes of Dart makes Dart unique in the world of programming languages - there are few languages that maintains three components (i.e. VM, compiler and transpiler). It's a lot of work for the Dart maintainers, but saves a lot of work for Dart developers.

Notable Characteristics

Built-In Asynchrony Support

Asynchronous programming is important for UI development because you don't want your UI to freeze when some time-consuming operation (e.g. network request, computationally heavy subroutines) is happening.

There are three major ways Dart supports asynchronous programming

Asynchronous programming is commonly used in UI because certain operations are not instant, most common of which is HTTP requests:

import 'dart:html';

main(List<String> args) {
  Future<String> respFuture = HttpRequest.getString('https://jsonplaceholder.typicode.com/todos/1');
  respFuture.then((result) => print(result));
  print("Hello world");
}

You should expect "Hello world" to be printed before the HTTP request's result because Future object makes sure that the progress of main will not be hindered by the HTTP request. Instead, callback function (result) => print(result) is called whenever the result is ready - thus asynchronous.

However it's possible to enforce the "line-by-line" execution order by using await in an async function:

import 'dart:html';

main(List<String> args) async {
  var result = await HttpRequest.getString('https://jsonplaceholder.typicode.com/todos/1');
  print(result);
  print("Hello world");
}

You may understand await as "waiting for the result, do not proceed until it's ready". .then and await are two different ways of consuming the result of a Future. To help you better understand the difference between async-await and then, here is an example:

Example


Extension Methods

Extension methods aim to solve one problem: when using an external library, you may want to extend or even change some of the methods for your own needs. For example, instead of using int.parse(42), you want to extend the String class so that it has a method parseInt() to parse a string to int. You can easily do so by extending String class in Dart:

extension NumberParsing on String {
  int parseInt() {
    return int.parse(this);
  }
}

main(List<String> args) {
  print('42'.parseInt());
}

Extending classes, especially core classes like String, could be quite tricky if not impossible without extension methods. However, in Dart, you can easily customize the behavior of built-in classes like so. Extension methods in Dart have even more interesting stuff like generic support.

Named Parameters

This is what makes declarative UI code written in Dart look surprisingly similar to JSON. In a language where the order of a function's parameters is specified by the function's definition, if you only look at the function call, it might be difficult for you to figure out what those parameters mean. One classic example is the put(key, value) of a Map data structure - if you only see m.put(1, 2), can you tell which one is key without prior knowledge?

That's when named parameters become handy:

When calling a function, you can specify named parameters using paramName: value. For example:

enableFlags(bold: true, hidden: false);

When defining a function, use {param1, param2, ...} to specify named parameters:

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}

Note that if named parameters are used, the order no longer matters, you can write enableFlags(hidden: false, bold: true); as well. This feature is especially useful for declarative UI as the properties of a widget are, most of the time, parameters passed to the constructor of the object. Below is a concrete example in Flutter. Imagine how messy and frustrating the code would look like if the parameters are not named and we have to refer to the documentation for the exact order of them!

// Copyright 2018 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Welcome to Flutter',
      home: Scaffold(
        appBar: AppBar(
          title: Text('Welcome to Flutter'),
        ),
        body: Center(
          child: Text('Hello World'),
        ),
      ),
    );
  }
}

Current State

Tooling support: Dart has out-of-the-box dependency management (pub.dev), linting solution (dartfmt), documentation generator (dartdoc) and official testing framework. After installing Dart SDK, you're ready to go 99% of the time.

Popularity: Dart is a relatively new (first appeared in 2011), but quickly gained popularity in recent years: it's ranked 16th the first time it entered the IEEE Spectrum programming language ranking, and 23rd on TIOBE as of April 2020. And Dart is being actively maintained by a team at Google: check out the GitHub repo of Dart SDK.

Limitations

Of course, like any other language, Dart is not perfect.

  • Even if Dart appears to be open-sourced, it has been pretty meaning the community contribution is more limited to bug fixes instead of adding new featuresinternally focused.
  • And unlike Java, C++ or Python, although technically you can write most types of application using Dart, it may not be your safest choice a lot of the times (i.e. you may find yourself writing Dart in a Flutter project most of the time).

How to Get Started With Dart?

Dart is well-documented and you should find solutions to most of your Dart problems on their website.

Like many devs who tried Dart says, you might already know Dart. If you already have any prior programming experience in any language (say, C, C++, Java, JavaScript, Python, Kotlin, Swift), you're pretty likely to master Dart within weeks for the following reasons:

  • Dart is using a C-style syntax: it won't be a surprise if a function written in Java can be compiled and run in Dart with minor (or no) changes.
  • Dart is a strongly-typed language with type-inference support: static typing makes IDE much more helpful and if your program compiles, it most likely works just fine.
  • You may find your favorite syntax (sugar) in Dart, for example
    • Similar to JavaScript: arrow functions
    • Similar to Kotlin: get and set keywords for OOP, null safety syntax

Getting Started