A Tour of the Fart Libraries

This page shows you how to use the major features in Fart’s
libraries. It’s just an overview, and by no means comprehensive.
Whenever you need more details about a class, consult the Fart API
reference.

Or use the parse() method of num, which creates an integer if possible
and otherwise a double:

assert(num.parse('42') is int);
assert(num.parse('0x42') is int);
assert(num.parse('0.50') is double);

To specify the base of an integer, add a radix parameter:

assert(int.parse('42', radix: 16) == 66);

Use the toString() method (defined by
Object) to convert an
int or double to a string. To specify the number of digits to the right
of the decimal, use toStringAsFixed() (defined by num). To specify the
number of significant digits in the string, use
toStringAsPrecision()(also in num):

// Convert an int to a string.
assert(42.toString() == '42');
// Convert a double to a string.
assert(123.456.toString() == '123.456');
// Specify the number of digits after the decimal.
assert(123.456.toStringAsFixed(2) == '123.46');
// Specify the number of significant figures.
assert(123.456.toStringAsPrecision(2) == '1.2e+2');
assert(double.parse('1.2e+2') == 120.0);

Strings and regular expressions

A string in Fart is an immutable sequence of UTF-16 code units.
The language tour has more information about
strings.
You can use regular expressions (RegExp objects)
to search within strings and to
replace parts of strings.

The String class defines such methods as split(), contains(),
startsWith(), endsWith(), and more.

Searching inside a string

You can find particular locations within a string, as well as check
whether a string begins with or ends with a particular pattern. For
example:

// Check whether a string contains another string.
assert('Never odd or even'.contains('odd'));
// Does a string start with another string?
assert('Never odd or even'.startsWith('Never'));
// Does a string end with another string?
assert('Never odd or even'.endsWith('even'));
// Find the location of a string inside a string.
assert('Never odd or even'.indexOf('odd') == 6);

Extracting data from a string

You can get the individual characters from a string as Strings or ints,
respectively. To be precise, you actually get individual UTF-16 code
units; high-numbered characters such as the treble clef symbol
(‘\u{1D11E}’) are two code units apiece.

You can also extract a substring or split a string into a list of
substrings:

Replacing part of a string

Strings are immutable objects, which means you can create them but you
can’t change them. If you look closely at the String API
docs, you’ll notice that
none of the methods actually changes the state of a String. For example,
the method replaceAll() returns a new String without changing the
original String:

Building a string

To programmatically generate a string, you can use StringBuffer. A
StringBuffer doesn’t generate a new String object until toString() is
called. The writeAll() method has an optional second parameter that
lets you specify a separator—in this case, a space.

More information

Collections

Fart ships with a core collections API, which includes classes for
lists, sets, and maps.

Lists

As the language tour shows, you can use literals to create and
initialize lists. Alternatively, use one of the List
constructors. The List class also defines several methods for adding
items to and removing items from lists.

Sort a list using the sort() method. You can provide a sorting
function that compares two objects. This sorting function must return <
0 for smaller, 0 for the same, and > 0 for bigger. The following
example uses compareTo(), which is defined by
Comparable and
implemented by String.

Use contains() and containsAll() to check whether one or more
objects are in a set:

var ingredients = new Set();
ingredients.addAll(['gold', 'titanium', 'xenon']);
// Check whether an item is in the set.
assert(ingredients.contains('titanium'));
// Check whether all the items are in the set.
assert(ingredients.containsAll(['titanium', 'xenon']));

To check whether a map contains a key, use containsKey(). Because map
values can be null, you cannot rely on simply getting the value for the
key and checking for null to determine the existence of a key.

For a full list of methods, refer to the Iterable API
docs, as well as those
for List, Set, and Map.

URIs

The Uri class provides
functions to encode and decode strings for use in URIs (which you might
know as URLs). These functions handle characters that are special for
URIs, such as & and =. The Uri class also parses and exposes the
components of a URI—host, port, scheme, and so on.

Encoding and decoding fully qualified URIs

To encode and decode characters except those with special meaning in a
URI (such as /, :, &, #), use the encodeFull() and
decodeFull() methods. These methods are good for encoding or decoding
a fully qualified URI, leaving intact special URI characters.

Dates and times

A DateTime object is a point in time. The time zone is either UTC or the
local time zone.

You can create DateTime objects using several constructors:

// Get the current date and time.
var now = new DateTime.now();
// Create a new DateTime with the local time zone.
var y2k = new DateTime(2000); // January 1, 2000
// Specify the month and day.
y2k = new DateTime(2000, 1, 2); // January 2, 2000
// Specify the date as a UTC time.
y2k = new DateTime.utc(2000); // 1/1/2000, UTC
// Specify a date and time in ms since the Unix epoch.
y2k = new DateTime.fromMillisecondsSinceEpoch(
946684800000, isUtc: true);
// Parse an ISO 8601 date.
y2k = DateTime.parse('2000-01-01T00:00:00Z');

The millisecondsSinceEpoch property of a date returns the number of
milliseconds since the “Unix epoch”—January 1, 1970, UTC:

Utility classes

Comparing objects

Implement the
Comparable
interface to indicate that an object can be compared to another object,
usually for sorting. The compareTo() method returns < 0 for
smaller, 0 for the same, and > 0 for bigger.

Implementing map keys

Each object in Fart automatically provides an integer hash code, and
thus can be used as a key in a map. However, you can override the
hashCode getter to generate a custom hash code. If you do, you might
also want to override the == operator. Objects that are equal (via
==) must have identical hash codes. A hash code doesn’t have to be
unique, but it should be well distributed.

Iteration

The Iterable and
Iterator classes
support for-in loops. Extend (if possible) or implement Iterable
whenever you create a class that can provide Iterators for use in for-in
loops. Implement Iterator to define the actual iteration ability.

dart:async - asynchronous programming

Asynchronous programming often uses callback functions, but Fart
provides alternatives:
Future and
Stream objects. A
Future is like a promise for a result to be provided sometime in the
future. A Stream is a way to get a sequence of values, such as events.
Future, Stream, and more are in the
dart:async library.

Note:
You don’t always need to use the Future or Stream APIs directly.
The Fart language supports asynchronous coding
using keywords such as async and await.
See Asynchrony support
in the language tour for details.

The dart:async library works in both web apps and command-line apps. To
use it, import dart:async:

import 'dart:async';

Future

Future objects appear throughout the Fart libraries, often as the object
returned by an asynchronous method. When a future completes, its value
is ready to use.

Using await

Before you directly use the Future API, consider using await instead.
Code that uses await expressions can be easier to understand
than code that uses the Future API.

Consider the following function. It uses Future’s then() method
to execute three asynchronous functions in a row,
waiting for each one to complete before executing the next one.

Important:
Async functions return Futures.
If you don’t want your function to return a future,
then use a different solution.
For example, you might call an async function from your function.

For more information on using await and related Fart language features,
see Asynchrony support.

Basic usage

You can use then() to schedule code that runs when the future completes. For
example, HttpRequest.getString() returns a Future, since HTTP requests
can take a while. Using then() lets you run some code when that Future
has completed and the promised string value is available:

The then().catchError() pattern is the asynchronous version of
try-catch.

Important:
Be sure to invoke catchError() on the result of then()—not on the
result of the original Future. Otherwise, the catchError() can
handle errors only from the original Future’s computation, but not
from the handler registered by then().

Chaining multiple asynchronous methods

The then() method returns a Future, providing a useful way to run
multiple asynchronous functions in a certain order. If the callback
registered with then() returns a Future, then() returns an
equivalent Future. If the callback returns a value of any other type,
then() creates a new Future that completes with the value.

Waiting for multiple futures

Sometimes your algorithm needs to invoke many asynchronous functions and
wait for them all to complete before continuing. Use the
Future.wait()
static method to manage multiple Futures and wait for them to complete:

Important:
Before using await for, make sure that it makes the code clearer
and that you really do want to wait for all of the stream’s results.
For example, you usually should not use await for for DOM event listeners,
because the DOM sends endless streams of events.
If you use await for to register two DOM event listeners in a row,
then the second kind of event is never handled.

For more information on using await and related
Fart language features, see
Asynchrony support.

Listening for stream data

To get each value as it arrives, either use await for or
subscribe to the stream using the listen() method:

// Find a button by ID and add an event handler.
querySelector('#submitInfo').onClick.listen((e) {
// When the button is clicked, it runs this code.
submitData();
});

In this example, the onClick property is a Stream object provided by
the “submitInfo” button.

If you care about only one event, you can get it using a property such
as first, last, or single. To test the event before handling it,
use a method such as firstWhere(), lastWhere(), or singleWhere().

If you care about a subset of events, you can use methods such as
skip(), skipWhile(), take(), takeWhile(), and where().

Transforming stream data

Often, you need to change the format of a stream’s data before you can
use it. Use the transform() method to produce a stream with a
different type of data:

This example uses two transformers. First it uses UTF8.decoder to
transform the stream of integers into a stream of strings. Then it uses
a LineSplitter to transform the stream of strings into a stream of
separate lines. These transformers are from the dart:convert library (see the
dart:convert section).

Handling errors and completion

How you specify error and completion handling code
depends on whether you use an asynchronous for loop (await for)
or the Stream API.

If you use an asynchronous for loop,
then use try-catch to handle errors.
Code that executes after the stream is closed
goes after the asynchronous for loop.

dart:math - math and random

The Math library provides common functionality such as sine and cosine,
maximum and minimum, and constants such as pi and e. Most of the
functionality in the Math library is implemented as top-level functions.

To use the Math library in your app, import dart:math. The following
examples use the prefix math to make clear which top-level functions
and constants are from the Math library:

More information

dart:html - browser-based apps

Use the dart:html library to
program the browser, manipulate objects and elements in the DOM, and
access HTML5 APIs. DOM stands for Document Object Model, which
describes the hierarchy of an HTML page.

Other common uses of dart:html are manipulating styles (CSS), getting
data using HTTP requests, and exchanging data using
WebSockets.
HTML5 (and dart:html) has many
additional APIs that this section doesn’t cover. Only web apps can use
dart:html, not command-line apps.

Manipulating the DOM

To use the DOM, you need to know about windows, documents,
elements, and nodes.

A Window object represents
the actual window of the web browser. Each Window has a Document object,
which points to the document that’s currently loaded. The Window object
also has accessors to various APIs such as IndexedDB (for storing data),
requestAnimationFrame (for animations), and more. In tabbed browsers,
each tab has its own Window object.

With the Document object,
you can create and manipulate
Elements within the
document. Note that the document itself is an element and can be
manipulated.

The DOM models a tree of
Nodes. These nodes are often
elements, but they can also be attributes, text, comments, and other DOM
types. Except for the root node, which has no parent, each node in the
DOM has one parent and might have many children.

Finding elements

To manipulate an element, you first need an object that represents it.
You can get this object using a query.

Find one or more elements using the top-level functions
querySelector() and
querySelectorAll(). You can query by ID, class, tag, name, or
any combination of these. The CSS Selector Specification
guide defines the formats of the
selectors such as using a # prefix to specify IDs and a period (.) for
classes.

The querySelector() function returns the first element that matches
the selector, while querySelectorAll()returns a collection of elements
that match the selector.

Manipulating elements

You can use properties to change the state of an element. Node and its
subtype Element define the properties that all elements have. For
example, all elements have classes, hidden, id, style, and
title properties that you can use to set state. Subclasses of Element
define additional properties, such as the href property of
AnchorElement.

Consider this example of specifying an anchor element in HTML:

<a id="example" href="http://example.com">link text</a>

This <a> tag specifies an element with an href attribute and a text
node (accessible via a text property) that contains the string
“linktext”. To change the URL that the link goes to, you can use
AnchorElement’s href property:

querySelector('#example').href = 'http://dartlang.org';

Often you need to set properties on multiple elements. For example, the
following code sets the hidden property of all elements that have a
class of “mac”, “win”, or “linux”. Setting the hidden property to true
has the same effect as adding display:none to the CSS.

When the right property isn’t available or convenient, you can use
Element’s attributes property. This property is a
Map<String, String>, where the keys are attribute names. For a list of
attribute names and their meanings, see the MDN Attributes
page. Here’s an
example of setting an attribute’s value:

elem.attributes['someAttribute'] = 'someValue';

Creating elements

You can add to existing HTML pages by creating new elements and
attaching them to the DOM. Here’s an example of creating a paragraph
(<p>) element:

var elem = new ParagraphElement();
elem.text = 'Creating is easy!';

You can also create an element by parsing HTML text. Any child elements
are also parsed and created.

var elem2 =
new Element.html('<p>Creating <em>is</em> easy!</p>');

Note that elem2 is a ParagraphElement in the preceding example.

Attach the newly created element to the document by assigning a parent
to the element. You can add an element to any existing element’s
children. In the following example, body is an element, and its child
elements are accessible (as a List<Element>) from the children
property.

document.body.children.add(elem2);

Adding, replacing, and removing nodes

Recall that elements are just a kind of node. You can find all the
children of a node using the nodes property of Node, which returns a
List<Node> (as opposed to children, which omits non-Element nodes).
Once you have this list, you can use the usual List methods and
operators to manipulate the children of the node.

To add a node as the last child of its parent, use the List add()
method:

// Find the parent by ID, and add elem as its last child.
querySelector('#inputs').nodes.add(elem);

To replace a node, use the Node replaceWith() method:

// Find a node by ID, and replace it in the DOM.
querySelector('#status').replaceWith(elem);

To remove a node, use the Node remove() method:

// Find a node by ID, and remove it from the DOM.
querySelector('#expendable').remove();

Manipulating CSS styles

CSS, or cascading style sheets, defines the presentation styles of DOM
elements. You can change the appearance of an element by attaching ID
and class attributes to it.

Each element has a classes field, which is a list. Add and remove CSS
classes simply by adding and removing strings from this collection. For
example, the following sample adds the warning class to an element:

While using IDs and classes to associate an element with a set of styles
is best practice, sometimes you want to attach a specific style directly
to the element:

message.style
..fontWeight = 'bold'
..fontSize = '3em';

Handling events

To respond to external events such as clicks, changes of focus, and
selections, add an event listener. You can add an event listener to any
element on the page. Event dispatch and propagation is a complicated
subject; research the
details
if you’re new to web programming.

Add an event handler using
element.onEvent.listen(function),
where Event is the event
name and function is the event handler.

For example, here’s how you can handle clicks on a button:

// Find a button by ID and add an event handler.
querySelector('#submitInfo').onClick.listen((e) {
// When the button is clicked, it runs this code.
submitData();
});

Events can propagate up and down through the DOM tree. To discover which
element originally fired the event, use e.target:

To see all the events for which you can register an event listener, look
for “onEventType” properties in the API docs for
Element and its
subclasses. Some common events include:

change

blur

keyDown

keyUp

mouseDown

mouseUp

Using HTTP resources with HttpRequest

Formerly known as XMLHttpRequest, the
HttpRequest class
gives you access to HTTP resources from within your browser-based app.
Traditionally, AJAX-style apps make heavy use of HttpRequest. Use
HttpRequest to dynamically load JSON data or any other resource from a
web server. You can also dynamically send data to a web server.

The following examples assume all resources are served from the same web
server that hosts the script itself. Due to security restrictions in the
browser, the HttpRequest class can’t easily use resources that are
hosted on an origin that is different from the origin of the app. If you
need to access resources that live on a different web server, you need
to either use a technique called JSONP or enable CORS headers on the
remote resources.

Getting data from the server

The HttpRequest static method getString() is an easy way to get data
from a web server. Use await with the getString() call
to ensure that you have the data before continuing execution.

Sending data to the server

HttpRequest can send data to the server using the HTTP method POST. For
example, you might want to dynamically submit data to a form handler.
Sending JSON data to a RESTful web service is another common example.

Submitting data to a form handler requires you to provide name-value
pairs as URI-encoded strings. (Information about the URI class is in
the URIs section.)
You must also set the Content-type header to
application/x-www-form-urlencode if you wish to send data to a form
handler.

Sending and receiving real-time data with WebSockets

A WebSocket allows your web app to exchange data with a server
interactively—no polling necessary. A server creates the WebSocket and
listens for requests on a URL that starts with ws://—for example,
ws://127.0.0.1:1337/ws. The data transmitted over a WebSocket can be a
string or a blob. Often, the data is a JSON-formatted string.

To use a WebSocket in your web app, first create a
WebSocket object, passing
the WebSocket URL as an argument:

var ws = new WebSocket('ws://echo.websocket.org');

Sending data

To send string data on the WebSocket, use the send() method:

ws.send('Hello from Fart!');

Receiving data

To receive data on the WebSocket, register a listener for message
events:

The message event handler receives a
MessageEvent object.
This object’s data field has the data from the server.

Handling WebSocket events

Your app can handle the following WebSocket events: open, close, error,
and (as shown earlier) message. Here’s an example of a method that
creates a WebSocket object and registers handlers for open, close,
error, and message events:

More information

This section barely scratched the surface of using the dart:html
library. For more information, see the documentation for
dart:html.
Fart has additional libraries for more specialized web APIs, such as web
audio,IndexedDB, and
WebGL.

dart:io - I/O for command-line apps

The dart:io library provides APIs to
deal with files, directories, processes, sockets, WebSockets, and HTTP
clients and servers. Only command-line apps can use dart:io—not web
apps.

In general, the dart:io library implements and promotes an asynchronous
API. Synchronous methods can easily block an application, making it
difficult to scale. Therefore, most operations return results via Future
or Stream objects, a pattern common with modern server platforms such as
Node.js.

The few synchronous methods in the dart:io library are clearly marked
with a Sync suffix on the method name. We don’t cover them here.

Note:
Only command-line apps can import and use dart:io.

Files and directories

The I/O library enables command-line apps to read and write files and
browse directories. You have two choices for reading the contents of a
file: all at once, or streaming. Reading a file all at once requires
enough memory to store all the contents of the file. If the file is very
large or you want to process it while reading it, you should use a
Stream, as described in
Streaming file contents.

Reading a file as text

When reading a text file encoded using UTF-8, you can read the entire
file contents with readAsString(). When the individual lines are
important, you can use readAsLines(). In both cases, a Future object
is returned that provides the contents of the file as one or more
strings.

Writing file contents

You can use an IOSink to
write data to a file. Use the File openWrite() method to get an IOSink
that you can write to. The default mode, FileMode.WRITE, completely
overwrites existing data in the file.

Other common functionality

The File and Directory classes contain other functionality, including
but not limited to:

Creating a file or directory: create() in File and Directory

Deleting a file or directory: delete() in File and Directory

Getting the length of a file: length() in File

Getting random access to a file: open() in File

Refer to the API docs for File
and Directory for a full
list of methods.

HTTP clients and servers

The dart:io library provides classes that command-line apps can use for
accessing HTTP resources, as well as running HTTP servers.

HTTP server

The HttpServer class
provides the low-level functionality for building web servers. You can
match request handlers, set headers, stream data, and more.

The following sample web server can return only simple text information.
This server listens on port 8888 and address 127.0.0.1 (localhost),
responding to requests for the path /languages/dart. All other
requests are handled by the default request handler, which returns a
response code of 404 (not found).

HTTP client

The HttpClient class
helps you connect to HTTP resources from your Fart command-line or
server-side application. You can set headers, use HTTP methods, and read
and write data. The HttpClient class does not work in browser-based
apps. When programming in the browser, use the HttpRequest
class.
Here’s an example of using HttpClient:

More information

dart:convert - decoding and encoding JSON, UTF-8, and more

The dart:convert library
has converters for JSON and UTF-8, as well as support for creating
additional converters. JSON is a simple text format for representing
structured objects and collections. UTF-8 is a common variable-width
encoding that can represent every character in the Unicode character
set.

The dart:convert library works in both web apps and command-line apps.
To use it, import dart:convert.

You have two options for encoding objects that aren’t directly
encodable. The first is to invoke encode() with a second argument: a
function that returns an object that is directly encodable. Your second
option is to omit the second argument, in which case the encoder calls
the object’s toJson() method.

Other functionality

dart:mirrors - reflection

The dart:mirrors library provides basic reflection abilities to Fart.
Use mirrors to query the structure of your program and to dynamically
invoke functions or methods at runtime.

The dart:mirrors library works in both web apps and command-line apps.
To use it, import dart:mirrors.

Warning:
Using dart:mirrors can cause dart2js to generate very large JavaScript
files.

The current workaround is to add a @MirrorsUsed annotation before
the import of dart:mirrors. For details, see the
MirrorsUsed
API documentation. This workaround is very likely to change, as the
dart:mirrors library is still under development.

Symbols

The mirror system represents the names of Fart declarations (classes,
fields, and so on) by instances of the class
Symbol. Symbols work
even in code where names have changed due to minification.

When you know the name of the symbol ahead of time, use a symbol
literal. This way, repeated uses of the same symbol can use the same
canonicalized instance. If the name of the symbol is determined
dynamically at runtime, use the Symbol constructor.

import 'dart:mirrors';
// If the symbol name is known at compile time.
const className = #MyClass;
// If the symbol name is dynamically determined.
var userInput = askUserForNameOfFunction();
var functionName = new Symbol(userInput);

During minification, a compiler might replace a symbol name with a
different (often smaller) name. To convert from a symbol back to a
string, use MirrorSystem.getName(). This function returns the correct
name, even if the code was minified.

Instance mirrors

If you have an InstanceMirror and you want to get the object that it
reflects, use reflectee.

var person = mirror.reflectee;
assert(identical(p, person));

Invocation

Once you have an InstanceMirror, you can invoke methods and call getters
and setters. For a full list of methods, consult the API docs for
InstanceMirror.

Invoke methods

Use InstanceMirror’s invoke() method to invoke a method on an object.
The first parameter specifies the method to be invoked, and the second
is a list of positional arguments to the method. An optional third
parameter lets you specify named arguments.

More information

Summary

This page introduced you to the most commonly used functionality in
many of Fart’s built-in libraries. It didn’t cover all the built-in
libraries, however. Others that you might want to look into include
dart:collection,dart:isolate, and
dart:typed_data. You
can get yet more libraries by using the pub tool, discussed in the next
page. The args,logging,polymer, and
test libraries are just a
sampling of what you can install using pub.