When Dart was originally launched, many developers mistook it for some sort of Java clone. In truth, Dart is inspired by a range of languages such as Smalltalk, Strongtalk, Erlang, C#, and JavaScript. Get past the semicolons and curly braces, and you’ll see a terse language without ceremony. Dart has evolved into its own, and here are some of my favorite language features.

Dart is a source code VM

The Dart VM reads and executes source code, which means there is no compile step between edit and run. As with other popular scripting languages, it’s very quick to iterate with Dart. The Dart VM runs on the command line and servers, and can be embedded into browsers. Just point the VM at Dart source code and you’re up and running!

Dart is optionally typed

Dart understands that sometimes you just don’t feel like appeasing a ceremonial type checker. Dart’s inclusion of an optional type system means you can use type annotations when you want, or use dynamic when that’s easier.

For example, you can explore a new idea without having to first think about type hierarchies. Just experiment and use var for your types. Once the idea is tested and you’re comfortable with the design, you can add type annotations.

Here is a comparison between code that uses type annotations, and code that uses var for dynamic. Both of these code snippets have the same runtime semantics:

With type annotations:

void advance(double dt) { double dx, dy, dz, distance, mag; int size = bodies.length; for (int i = 0; i < size; i++) { Body bodyi = bodies[i]; // ... 1 2 3 4 5 6 void advance ( double dt ) { double dx , dy , dz , distance , mag ; int size = bodies . length ; for ( int i = 0 ; i < size ; i ++ ) { Body bodyi = bodies [ i ] ; // ...

Or, without type annotations:

advance(dt) { var dx, dy, dz, distance, mag; var size = bodies.length; for (var i = 0; i < size; i++) { var bodyi = bodies[i]; // … 1 2 3 4 5 6 advance ( dt ) { var dx , dy , dz , distance , mag ; var size = bodies . length ; for ( var i = 0 ; i < size ; i ++ ) { var bodyi = bodies [ i ] ; // …

Type annotations are great for the “surface area” of the code (such as method and function signatures), and the tools are getting good enough for you to consider using var inside methods and functions.

Dart supports collection literals

It’s easy to declare lists and maps with Dart. For example, here is a simple list:

var fruits = ['apples', 'oranges', 'pears']; 1 var fruits = [ 'apples' , 'oranges' , 'pears' ] ;

And here is a simple map:

var accounts = {'322532': new Account('Bob'), '43534345': new Account('Alice')}; 1 var accounts = { '322532' : new Account ( 'Bob' ) , '43534345' : new Account ( 'Alice' ) } ;

Dart is purely object oriented

Dart’s language is clear: everything is an object. It is easy to explain how everything works without having to deal with primitives as a special case. Even calling + on two numbers is modeled as a method call. Numbers, booleans, and even null are all objects.

Dart supports top-level functions and variables

Not everything must live inside of a class. Dart’s libraries can contain top-level functions and variables. You can write whole programs without ever using a class.

Here is a simple Dart library:

library louder; String shout(String msg) => msg.toUpperCase(); 1 2 3 library louder ; String shout ( String msg ) = > msg . toUpperCase ( ) ;

Using this library is easy:

import 'louder.dart'; main() { print(shout('Dart is fun!')); // DART IS FUN! } 1 2 3 4 5 import 'louder.dart' ; main ( ) { print ( shout ( 'Dart is fun!' ) ) ; // DART IS FUN! }

Dart’s main function is terse

No more public-static-void-main-String[]-args just to start a program! Dart’s simple top-level main() function is all you need.

Here is an example:

main() { print('Hello, Dart!'); } 1 2 3 main ( ) { print ( 'Hello, Dart!' ) ; }

All Dart programs start at the main() function.

Dart lets you put any number of public classes into a file

Organize your project’s files and contents the way you want to. You are not forced to name the file the same as the class, and you aren’t forced to place only one public class in a file. Go ahead, put two classes into one file. Whatever works for you!

Dart has closures and lexically scoped functions

Create functions that can naturally access variables in their enclosing scope, without having to write verbose anonymous inner classes.

Here is an example of a closure in action. The makeAdder function returns a function that closes around makeAdder ‘s parameter.

makeAdder(int x) { adder(int y) => x + y; return adder; } main() { var add2 = makeAdder(2); var result = add2(3); print(result); // 5 } 1 2 3 4 5 6 7 8 9 10 makeAdder ( int x ) { adder ( int y ) = > x + y ; return adder ; } main ( ) { var add2 = makeAdder ( 2 ) ; var result = add2 ( 3 ) ; print ( result ) ; // 5 }

You can use simplify makeAdder by returning an anonymous function:

makeAdder(int x) { return (int y) => x + y; } 1 2 3 makeAdder ( int x ) { return ( int y ) = > x + y ; }

Dart has mixins

No need to pollute the inheritance hierarchy with utility classes. Use Dart’s mixins to slide in functionality that is clearly not an is-a relationship.

Classes that extend object, don’t have constructors, and don’t call super can be a mixin. Here is an example:

abstract class Persistable { save() { ... } load() { ... } toJson(); } class Hug extends Object with Persistable { Map toJson() => {'strength':10}; } main() { var embrace = new Hug(); embrace.save(); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 abstract class Persistable { save ( ) { . . . } load ( ) { . . . } toJson ( ) ; } class Hug extends Object with Persistable { Map toJson ( ) = > { 'strength' : 10 } ; } main ( ) { var embrace = new Hug ( ) ; embrace . save ( ) ; }

Dart has operator overriding

You can add operators to your class. Here is an example:

class Point { num x, y; Point(this.x, this.y); Point operator +(Point other) => new Point(x+other.x, y+other.y); } main() { var p1 = new Point(1, 1); var p2 = new Point(2, 2); var p3 = p1 + p2; } 1 2 3 4 5 6 7 8 9 10 11 12 class Point { num x , y ; Point ( this . x , this . y ) ; Point operator + ( Point other ) = > new Point ( x + other . x , y + other . y ) ; } main ( ) { var p1 = new Point ( 1 , 1 ) ; var p2 = new Point ( 2 , 2 ) ; var p3 = p1 + p2 ; }

Dart has string interpolation

It’s very easy to build a string from variables or expressions. Here is an example of implementing toString() and including the x and y fields in the output.

// Dart class Point { num x, y; Point(this.x, this.y); String toString() => 'X: $x, Y: $y'; } 1 2 3 4 5 6 7 // Dart class Point { num x , y ; Point ( this . x , this . y ) ; String toString ( ) = > 'X: $x, Y: $y' ; }

Dart has noSuchMethod

A class can implement noSuchMethod to handle methods that don’t explicitly exist on the class.

In the following example, the LoggingProxy logs all method calls before they are delegated. The code uses mirrors for run-time reflection and delegation, and noSuchMethod to capture the calls.

import 'dart:mirrors'; class LoggingProxy { InstanceMirror mirror; LoggingProxy(delegate) : mirror = reflect(delegate); noSuchMethod(Invocation invocation) { var name = invocation.memberName; print('${name} was called'); return mirror.delegate(invocation); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 import 'dart:mirrors' ; class LoggingProxy { InstanceMirror mirror ; LoggingProxy ( delegate ) : mirror = reflect ( delegate ) ; noSuchMethod ( Invocation invocation ) { var name = invocation . memberName ; print ( '${name} was called' ) ; return mirror . delegate ( invocation ) ; } }

You can use the above code like this:

class Greeter { hello() => print("hello!"); } void main() { var greeter = new LoggingProxy(new Greeter()); greeter.hello(); } // Output is: // Symbol("hello") was called (from the proxy) // hello! (from the delegate Greeter) 1 2 3 4 5 6 7 8 9 10 11 12 class Greeter { hello ( ) = > print ( "hello!" ) ; } void main ( ) { var greeter = new LoggingProxy ( new Greeter ( ) ) ; greeter . hello ( ) ; } // Output is: // Symbol("hello") was called (from the proxy) // hello! (from the delegate Greeter)

Summary

Dart is a pragmatic language designed for adoption, and its familiar syntax and productive features make it easy to learn. Dart compiles to JavaScript and runs across the modern web, and it scales from tens of lines to one million lines of code. With its stable language and core libraries, you can use it today. Visit dartlang.org for more info and download the open-source SDK. See you at FluentConf!

Editor’s note: If you’d like to see more from Seth, check out his interview with Simon St. Laurent. For more information on Dart, see What is Dart? by Kathy Walrath and Seth Ladd.