Introducing Dart Programming Language & Special Features

Phuoc Ngo.T
SK Geek
Published in
8 min readApr 3, 2018

--

Introducing Dart Language

Dart is a new language using C-style which is developed by Google (designed by Lars Bak and Kasper Lund). It appeared first time in 2007 and the latest stable release is in June 2017. So it's not too “new", right?!! Not many people had known about Dart, until recent days, with the strong growth of Flutter (developed by Google) , it becomes more popular.

Dart is used for developing web, server, mobile applications and some IoT devices. It is open-source software with BSD license.

// This is where the app starts executing.
main() {
print('Hello world'); // Call a function.
}

Assuming that you have basic knowledge about programming language, in this blog I just mentioned about special features and things which is different from other languages. ( looks like it’s not too much, hah. But it's not! )

Before we go, you can use DartPad to write your Dart sample code.

Concepts

Dart is object-oriented, class-based, optionally typed and support mixin-base inheritance. There are some principles you need to keep in minds when working with Dart:

  • Everything is an object, every object is an instance of class. All objects inherit from Object class.
  • Specifying static types clarifies your intent and enables static checking by tools.
  • Dart parses all your code before running it.

Special Features

Following are features or principles you need to notice when working with Dart.

Keywords

As other languages, Dart has almost normal keywords. But please remember, we don't have public, protected, and private in Dart. Instead of, using underscore (_) before an identifier to make it private to its library.

Variables

var name = 'Bob';

Variables are references. The variable called name contains a reference to a String object with a value of “Bob”.

As I mentioned above, everything (even number) in Dart is an object. It means, uninitialized variables have value of null.

int lineCount;
assert(lineCount == null);
// Variables (even if they will be numbers) are initially null.

Built-in Types

There are types which are supported by Dart:

  • Number: int and double
  • Strings: A Dart string is a sequence of UTF-16 code units
  • Booleans: Dart has a type named bool . Only two objects have type bool: the boolean literals true and false . This is an important thing, please keep in mind that only the value true is treated as true. All other values are treated as false.
var name = 'Bob';
if (name) {
// Prints in JavaScript, not in Dart.
print('You have a name!');
}
if (1) {
print('JS prints this line.');
} else {
print('Dart in production mode prints this line.');
// However, in checked mode, if (1) throws an
// exception because 1 is not boolean.
}
  • Lists: In Dart, arrays are list objects.
  • Maps: a map is an object that associates keys and values. Both keys and values can be any type of object.
  • Runes: runes are the UTF-32 code points of a string.
  • Symbols: A Symbol object represents an operator or identifier declared in a Dart program.

Functions

Function is also an object. This means that you can assign a function to a variable or pass as arguments to other functions.

bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}

For functions that contain just one expression, you can use a shorthand syntax:

bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

The => expr syntax is a shorthand for { return expr; }

Dart is a lexically scoped language, so you can use nested function:

bool topLevel = true;

void main() {
var insideMain = true;

void myFunction() {
var insideFunction = true;

void nestedFunction() {
var insideNestedFunction = true;

assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}

Operators

About arithmetic operators, we have new “~/” (divide, returning an integer result).

About type test operators, we have as (typecast), is (true if the object has the specified type) and is! (false if the object has the specified type).

Cascade notation (..)

Dart provide cascade (..) to make a sequence of operations on the same object. Look at following code:

querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));

The first method call, querySelector(), returns a selector object. The code that follows the cascade notation operates on this selector object, ignoring any subsequent values that might be returned.

The previous example is equivalent to:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

When using cascade (..) please make sure that the first call function return an object. Otherwise, it will fail with error.

Classes

Dart is object-oriented, class-based, optionally typed and support mixin-base inheritance.

Constructors

Like other languages, this is the most common constructor:

class Point {
num x, y;

Point(num x, num y) {
// There's a better way to do this, stay tuned.
this.x = x;
this.y = y;
}
}

Dart has syntactic sugar to make constructor above look more pretty:

class Point {
num x, y;

// Syntactic sugar for setting x and y
// before the constructor body runs.
Point(this.x, this.y);
}

Constructors aren’t inherited by subclass. If subclass don't provide a constructor, a default constructor will be provided.

If you want to implement multiple constructor for reasons, use named constructor as below:

class Point {
num x, y;

Point(this.x, this.y);

// Named constructor
Point.origin() {
x = 0;
y = 0;
}
}

As I mentioned above, constructors aren't inherited. So by default, subclass don't have named constructor of superclass. If you want to construct subclass by using named contructors of superclass, specify the superclass constructor after a colon (:), just before the constructor body (if any):

class Person {
String firstName;
Person.fromJson(Map data) {
print('in Person');
}
}
class Employee extends Person { // Person does not have a default constructor;
// you must call super.fromJson(data).
Employee.fromJson(Map data) : super.fromJson(data) {
print('in Employee');
}
}

You can also initialize instance variables before the constructor body runs (separate initializers with commas):

// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}

You can use redirecting constructor in case a constructor just only want to redirect to another constructor in same class:

class Point {
num x, y;

// The main constructor for this class.
Point(this.x, this.y);

// Delegates to the main constructor.
Point.alongXAxis(num x) : this(x, 0);
}

To create a factory constructor, use factory keyword:

class Logger {
final String name;
bool mute = false;

// _cache is library-private, thanks to
// the _ in front of its name.
static final Map<String, Logger> _cache =
<String, Logger>{};

factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = new Logger._internal(name);
_cache[name] = logger;
return logger;
}
}

Logger._internal(this.name);

void log(String msg) {
if (!mute) print(msg);
}
}

Mixins

Mixins are a way of reusing a class’s code in multiple class hierarchies. In other words, if you want to use other classes's code but don't want to inherit that classes (basically, a class just can only have 1 super class), use Mixins.

To implement a mixin, create a class that extends Object, declares no constructors, and has no calls to super. For example:

abstract class Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;

void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}

Then in the class which want to use mixin, add keyword with followed by mixins name:

class Musician extends Performer with Musical {
// ···
}

class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}

Callable classes

To make your Dart class be called like function, implement the call() method:

class WannabeFunction {
call(String a, String b, String c) => '$a $b $c!';
}
main() {
var wf = new WannabeFunction();
var out = wf("Hi","there,","gang");
print('$out');
}

Generics

Dart also support generic type. Basiccally, it just like other languages. There are some parts you may want to notice:

  • Using extends if you want to limit generic type:
class Foo<T extends SomeBaseClass> {
// ···
}
  • Dart supports a newer syntax, called generic methods, allow type arguments on methods and functions:
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
T tmp = ts[0];
// Do some additional checking or processing...
return tmp;
}

Asynchronous functions

Dart provides Future and Stream object to support asynchronous functions.

Futures

As it's name, Future means return value will be returned at some time in the future. ( Sound like Promises, hah !)

Future<int> future = new Future(foo);  // Result of foo() as a future.
future.then((int value) => bar(value))
.catchError((e) => 499);

the asynchronous code above equivalent to synchronous code below:

// Synchronous code.
try {
int value = foo();
return bar(value);
} catch (e) {
return 499;
}

To get the final result of Future, you can use .then followed by block codes like above. Or, to make the code look like synchronous code, you can use async and await.

Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}

The code above look likes synchronous function, but it's not. You may notice the keyword async . To use await, code must be in a function marked as async . It's important. A function which want to return a Future need to be marked as async too.

One more thing, you can use try, catch, and finally to handle errors and cleanup in code that uses await .

Streams

A Stream support to receive a sequence of events (both data and error). To get values from a Stream, use can use async and an asynchronous for loop (await for). Below is example of asynchronous for loop:

await for (varOrType identifier in expression) {
// Executes each time the stream emits a value.
}

The expression above must be a Stream's subclass. Execution proceeds as follows:

  1. Wait until the stream emits a value.
  2. Execute the body of the for loop, with the variable set to that emitted value.
  3. Repeat 1 and 2 until the stream is closed.

What's next ?

Okay. I think it's enough for main points in Dart. You can take a deep dive into Dart with reference link below.

As I said at the top, there are many places you can do with Dart. So after you are familiar to Dart, you can try these frameworks:

  • For mobile application, we have Flutter.
  • For web page, we have AngularDart.
  • For server or virtual machine, we have DartVM.

Hope you will enjoy with Dart.

Reference

https://www.dartlang.org/guides/language/language-tour

--

--