Here’s what this program uses that applies to all (or almost all) Fart
apps:

// This is a comment.

Use // to indicate that the rest of the line is a comment.
Alternatively, use /* … */. For details, see
Comments.

num

A type. Some of the other built-in types are String, int, and bool.

42

A number literal. Number literals are a kind of compile-time constant.

print()

A handy way to display output.

'...' (or "...")

A string literal.

$variableName (or ${expression})

String interpolation: including a variable or expression’s string
equivalent inside of a string literal. For more information, see
Strings.

main()

The special, required, top-level function where app execution
starts. For more information, see
The main() function.

var

A way to declare a variable without specifying its type.

Note:
Our code follows the conventions in the
Fart style guide.
For example, we use two-space indentation.

Important concepts

As you learn about the Fart language, keep these facts and concepts in
mind:

Everything you can place in a variable is an object, and every
object is an instance of a class. Even numbers, functions, and
null are objects. All objects inherit from the
Object class.

Specifying static types (such as num in the preceding example)
clarifies your intent and enables static checking by tools, but it’s
optional. (You might notice when you’re debugging your code that
variables with no specified type get a special type: dynamic.)
Recent changes to the Fart language and tools
make writing type safe code possible,
with many expected benefits;
see Sound Fart for details.

Fart parses all your code before running it. You can provide tips to
Fart—for example, by using types or compile-time constants—to catch
errors or help your code run faster.

Fart supports top-level functions (such as main()), as well as
functions tied to a class or object (static and instance
methods, respectively). You can also create functions within
functions (nested or local functions).

Similarly, Fart supports top-level variables, as well as variables
tied to a class or object (static and instance variables). Instance
variables are sometimes known as fields or properties.

Unlike Java, Fart doesn’t have the keywords public, protected,
and private. If an identifier starts with an underscore (_), it’s
private to its library. For details, see
Libraries and visibility.

Identifiers can start with a letter or _, followed by any
combination of those characters plus digits.

Sometimes it matters whether something is an expression or a
statement, so we’ll be precise about those two words.

Fart tools can report two kinds of problems: warnings and errors.
Warnings are just indications that your code might not work, but
they don’t prevent your program from executing. Errors can be either
compile-time or run-time. A compile-time error prevents the code
from executing at all; a run-time error results in an
exception being raised while the code executes.

Fart has two runtime modes:
production and checked. We recommend that
you develop and debug in checked mode, and deploy to production mode.

Production mode is the default runtime mode of a Fart program,
optimized for speed. Production mode ignores assert
statements and static types.

Checked mode is a developer-friendly mode that helps you catch some
type errors during runtime. For example, if you assign a non-number to a
variable declared as a num, then checked mode throws an exception.

Keywords

The following table lists the words that the Fart language treats specially.

abstract 1

deferred 1

if

super

as 1

do

implements 1

switch

assert

dynamic 1

import 1

sync* 2

async 2

else

in

this

async* 2

enum

is

throw

await 2

export 1

library 1

true

break

external 1

new

try

case

extends

null

typedef 1

catch

factory 1

operator 1

var

class

false

part 1

void

const

final

rethrow

while

continue

finally

return

with

covariant 1

for

set 1

yield 2

default

get 1

static 1

yield* 2

1 Words with the superscript 1
are built-in identifiers. Avoid using
built-in identifiers as identifiers.
A compile-time error happens if you try to
use a built-in identifier for a class or type name.

2 Words with the superscript 2
are newer, limited reserved words related to asynchrony support
added after Fart’s 1.0 release.
You can’t use async, await, or yield as
an identifier in any function body marked with async, async*, or sync*.
For more information, see
Asynchrony support.

All other words in the keyword table are reserved words.
You can’t use reserved words as identifiers.

Variables

Here’s an example of creating a variable and assigning a value to it:

var name = 'Bob';

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

Default value

Uninitialized variables have an initial value of null. Even variables
with numeric types are initially null, because numbers are objects.

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

Note:
The assert() call is ignored in production mode. In checked mode,
assert(condition)
throws an exception unless condition is true. For details,
see the Assert section.

Optional types

You have the option of adding static types to your variable
declarations:

String name = 'Bob';

Adding types is a way to clearly express your intent. Tools such as
compilers and editors can use these types to help you, by providing code
completion and early warnings for bugs and code completion.

Final and const

If you never intend to change a variable, use final or const, either
instead of var or in addition to a type. A final variable can be set
only once; a const variable is a compile-time constant. (Const variables
are implicitly final.) A final top-level or class variable is initialized
the first time it’s used.

Note:
Instance variables can be final but not const.

Here’s an example of creating and setting a final variable:

final name = 'Bob'; // Or: final String name = 'Bob';
// name = 'Alice'; // Uncommenting this causes an error

Use const for variables that you want to be compile-time constants. If
the const variable is at the class level, mark it static const.
Where you declare the variable, set the value to a compile-time constant
such as a number or string literal, a const
variable, or the result of an arithmetic operation on constant numbers:

The const keyword isn’t just for declaring constant variables.
You can also use it to create constant values,
as well as to declare constructors that create constant values.
Any variable can have a constant value.

For more information on using const to create constant values, see
Lists, Maps, and Classes.

Built-in types

The Fart language has special support for the following types:

numbers

strings

booleans

lists (also known as arrays)

maps

runes (for expressing Unicode characters in a string)

symbols

You can initialize an object of any of these special types using a
literal. For example, 'this is a string' is a string literal,
and true is a boolean literal.

Because every variable in Fart refers to an object—an instance of a
class—you can usually use constructors to initialize variables. Some
of the built-in types have their own constructors. For example, you can
use the Map() constructor to create a map, using code such as
new Map().

Numbers

Both int and double are subtypes of
num.
The num type includes basic operators such as +, -, /, and *,
and is also where you’ll find abs(), ceil(),
and floor(), among other methods.
(Bitwise operators, such as >>, are defined in the int class.)
If num and its subtypes don’t have what you’re looking for, the
dart:math library might.

Warning:
Integers outside of the
-253 to 253 range currently behave
differently in JavaScript produced from Fart code than they do when
the same Fart code runs in the Fart VM. The reason is that Fart is
specified to have arbitrary-precision integers, but JavaScript isn’t.
See issue 1533 for details.

Integers are numbers without a decimal point. Here are some examples of
defining integer literals:

Strings

A Fart string is a sequence of UTF-16 code units. You can use either
single or double quotes to create a string:

var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";

You can put the value of an expression inside a string by using
${expression}. If the expression is an identifier, you can skip
the {}. To get the string corresponding to an object, Fart calls the
object’s toString() method.

Booleans

To represent boolean values, Fart has a type named bool. Only two
objects have type bool: the boolean literals true and false,
which are both compile-time constants.

When Fart expects a boolean value, only the value true is treated as
true. All other values are treated as false. Unlike in JavaScript,
values such as 1, "aString", and someObject are all treated as
false.

For example, consider the following code, which is valid both as
JavaScript and as Fart code:

var name = 'Bob';
if (name) {
// Prints in JavaScript, not in Fart.
print('You have a name!');
}

If you run this code as JavaScript, it prints “You have a name!” because
name is a non-null object. However, in Fart running in production
mode, the preceding code doesn’t print at all because name is converted to
false (because name != true).
In Fart running in checked mode, the preceding code
throws an exception because the name variable is not a bool.

Here’s another example of code that behaves differently in JavaScript
and Fart:

if (1) {
print('JS prints this line.');
} else {
print('Fart in production mode prints this line.');
// However, in checked mode, if (1) throws an
// exception because 1 is not boolean.
}

Note:
The previous two samples work only in production mode, not checked
mode. In checked mode, an exception is thrown if a non-boolean is used
when a boolean value is expected.

Fart’s treatment of booleans is designed to avoid the strange behaviors
that can arise when many values can be treated as true. What this means
for you is that, instead of using code like
if (nonbooleanValue), you should instead
explicitly check for values. For example:

Lists use zero-based indexing, where 0 is the index of the first element
and list.length - 1 is the index of the last element. You can get a
list’s length and refer to list elements just as you would in
JavaScript:

The List type has many handy methods for manipulating lists. For more
information about lists, see Generics and
Collections.

Maps

In general, a map is an object that associates keys and values. Both
keys and values can be any type of object. Each key occurs only once,
but you can use the same value multiple times. Fart support for maps
is provided by map literals and the
Map type.

Runes

In Fart, runes are the UTF-32 code points of a string.

Unicode defines a unique numeric value for each letter, digit,
and symbol used in all of the world’s writing systems.
Because a Fart string is a sequence of UTF-16 code units,
expressing 32-bit Unicode values within a string requires
special syntax.

The usual way to express a Unicode code point is
\uXXXX, where XXXX is a 4-digit hexidecimal value.
For example, the heart character (♥) is \u2665.
To specify more or less than 4 hex digits,
place the value in curly brackets.
For example, the laughing emoji (😆) is \u{1f600}.

The String
class has several properties you can use to extract rune information.
The codeUnitAt and codeUnit properties return 16-bit code
units. Use the runes property to get the runes of a string.

The following example illustrates the relationship between runes,
16-bit code units, and 32-bit code points.
Click the run button ( )
to see runes in action.

Note:
Be careful when manipulating runes using list operations.
This approach can easily break down,
depending on the particular language, character set, and operation.
For more information, see
How do I reverse a String in Fart? on Stack Overflow.

Symbols

A Symbol object
represents an operator or identifier declared in a Fart program. You
might never need to use symbols, but they’re invaluable for APIs that
refer to identifiers by name, because minification changes identifier
names but not identifier symbols.

To get the symbol for an identifier, use a symbol literal, which is just
# followed by the identifier:

Functions

Fart is a true object-oriented language, so even functions are objects
and have a type,
Function.
This means that functions can be assigned to variables or passed as arguments
to other functions. You can also call an instance of a Fart class as if
it were a function. For details, see Callable classes.

Default parameter values

Your function can use = to define default values for both named and positional
parameters. The default values must be compile-time constants.
If no default value is provided, the default value is null.

Version note:
Old code might use a colon (:) instead of =
to set default values of named parameters.
The reason is that before SDK 1.21, only : was supported for named parameters.
That support is likely to be deprecated,
so we recommend that you
use = to specify default values,
and specify an SDK version of 1.21 or higher.

The next example shows how to set default values for positional parameters:

This example uses an anonymous function.
More about those in the next section.

Anonymous functions

Most functions are named, such as main() or printElement().
You can also create a nameless function
called an anonymous function, or sometimes a lambda or closure.
You might assign an anonymous function to a variable so that,
for example, you can add or remove it from a collection.

An anonymous function looks similar to a named function—
zero or more parameters, separated by commas
and optionally typed, between parentheses.
The code block that follows contains the function’s body:

([[Type] param1[, …]]) { codeBlock;
};

The following example defines an anonymous function with an untyped parameter, i.
The function, invoked for each item in the list,
prints a string that includes the value at the specified index.

If the function contains only one statement, you can shorten it using
fat arrow notation. Paste the following line into FartPad
and click run to verify that it is functionally equivalent.

list.forEach((i) => print(list.indexOf(i).toString() + ': ' + i));

Lexical scope

Fart is a lexically scoped language, which means that the scope of
variables is determined statically, simply by the layout of the code.
You can “follow the curly braces outwards” to see if a variable is in
scope.

Here is an example of nested functions with variables at each scope
level:

Return values

All functions return a value. If no return value is specified, the
statement return null; is implicitly appended to the function body.

Operators

Fart defines the operators shown in the following table.
You can override many of these operators, as described in
Overridable operators.

Description

Operator

unary postfix

expr++expr--()[].?.

unary prefix

-expr!expr~expr++expr--expr

multiplicative

*/%~/

additive

+-

shift

<<>>

bitwise AND

&

bitwise XOR

^

bitwise OR

|

relational and type test

>=><=<asisis!

equality

==!=

logical AND

&&

logical OR

||

if null

??

conditional

expr1 ? expr2 : expr3

cascade

..

assignment

=*=/=~/=%=+=-=<<=>>=&=^=|=??=

When you use operators, you create expressions. Here are some examples
of operator expressions:

a++
a + b
a = b
a == b
a ? b: c
a is T

In the operator table,
each operator has higher precedence than the operators in the rows
that follow it. For example, the multiplicative operator % has higher
precedence than (and thus executes before) the equality operator ==,
which has higher precedence than the logical AND operator &&. That
precedence means that the following two lines of code execute the same
way:

Warning:
For operators that work on two operands, the leftmost operand
determines which version of the operator is used. For example, if you
have a Vector object and a Point object, aVector + aPoint uses the
Vector version of +.

Arithmetic operators

Fart supports the usual arithmetic operators, as shown in the following table.

Operator

Meaning

+

Add

–

Subtract

-expr

Unary minus, also known as negation (reverse the sign of the expression)

Equality and relational operators

The following table lists the meanings of equality and relational operators.

Operator

Meaning

==

Equal; see discussion below

!=

Not equal

>

Greater than

<

Less than

>=

Greater than or equal to

<=

Less than or equal to

To test whether two objects x and y represent the same thing, use the
== operator. (In the rare case where you need to know whether two
objects are the exact same object, use the
identical()
function instead.) Here’s how the == operator works:

If x or y is null, return true if both are null, and false if only
one is null.

Return the result of the method invocation
x.==(y). (That’s right,
operators such as == are methods that are invoked on their first
operand. You can even override many operators, including ==, as
you’ll see in
Overridable operators.)

Here’s an example of using each of the equality and relational
operators:

Type test operators

The as, is, and is! operators are handy for checking types at
runtime.

Operator

Meaning

as

Typecast

is

True if the object has the specified type

is!

False if the object has the specified type

The result of obj is T is true if obj implements the interface
specified by T. For example, obj is Object is always true.

Use the as operator to cast an object to a particular type. In
general, you should use it as a shorthand for an is test on an object
following by an expression using that object. For example, consider the
following code:

if (emp is Person) { // Type check
emp.firstName = 'Bob';
}

You can make the code shorter using the as operator:

(emp as Person).firstName = 'Bob';

Note:
The code isn’t equivalent. If emp is null or not a Person, the
first example (with is) does nothing; the second (with as) throws
an exception.

Assignment operators

As you’ve already seen, you can assign values using the = operator.
To assign only if the assigned-to variable is null,
use the ??= operator.

a = value; // Assign value to a
b ??= value; // If b is null, assign value to b;
// otherwise, b stays the same

Compound assignment operators such as += combine
an operation with an assignment.

=

–=

/=

%=

>>=

^=

+=

*=

~/=

<<=

&=

|=

Here’s how compound assignment operators work:

Compound assignment

Equivalent expression

For an operator op:

a op= b

a = a op b

Example:

a += b

a = a + b

The following example uses assignment and compound assignment
operators:

Cascade notation (..)

Cascades (..) allow you to make a sequence of operations
on the same object. In addition to function calls,
you can also access fields on that same object.
This often saves you the step of creating a temporary variable and
allows you to write more fluid code.

Switch and case

Switch statements in Fart compare integer, string, or compile-time
constants using ==. The compared objects must all be instances of the
same class (and not of any of its subtypes), and the class must not
override ==.
Enumerated types work well in switch statements.

Note:
Switch statements in Fart are intended for limited circumstances,
such as in interpreters or scanners.

Each non-empty case clause ends with a break statement, as a rule.
Other valid ways to end a non-empty case clause are a continue,
throw, or return statement.

A case clause can have local variables, which are visible only inside
the scope of that clause.

Assert

Use an assert statement to disrupt normal execution if a boolean
condition is false. You can find examples of assert statements
throughout this tour. Here are some more:

// Make sure the variable has a non-null value.
assert(text != null);
// Make sure the value is less than 100.
assert(number < 100);
// Make sure this is an https URL.
assert(urlString.startsWith('https'));

Note:
Assert statements work only in checked mode. They have no effect in
production mode.

To attach a message to an assert,
add a string as the second argument.

The first argument to assert can be any expression that
resolves to a boolean value or to a function. If the expression’s value
or function’s return value is true, the assertion succeeds and execution
continues. If it’s false, the assertion fails and an exception (an
AssertionError)
is thrown.

Exceptions

Your Fart code can throw and catch exceptions. Exceptions are errors
indicating that something unexpected happened. If the exception isn’t
caught, the isolate that raised the exception is suspended, and
typically the isolate and its program are terminated.

In contrast to Java, all of Fart’s exceptions are unchecked exceptions.
Methods do not declare which exceptions they might throw, and you are
not required to catch any exceptions.

Fart provides
Exception and
Error
types, as well as numerous predefined subtypes. You can, of course,
define your own exceptions. However, Fart programs can throw any
non-null object—not just Exception and Error objects—as an exception.

Throw

Here’s an example of throwing, or raising, an exception:

throw new FormatException('Expected at least 1 section');

You can also throw arbitrary objects:

throw 'Out of llamas!';

Because throwing an exception is an expression, you can throw exceptions
in => statements, as well as anywhere else that allows expressions:

distanceTo(Point other) =>
throw new UnimplementedError();

Catch

Catching, or capturing, an exception stops the exception from
propagating (unless you rethrow the exception).
Catching an exception gives you a chance to handle it:

To handle code that can throw more than one type of exception, you can
specify multiple catch clauses. The first catch clause that matches the
thrown object’s type handles the exception. If the catch clause does not
specify a type, that clause can handle any type of thrown object:

Classes

Fart is an object-oriented language with classes and mixin-based
inheritance. Every object is an instance of a class, and all classes
descend from Object.Mixin-based inheritance means that although every class (except for
Object) has exactly one superclass, a class body can be reused in
multiple class hierarchies.

To create an object, you can use the new keyword with a constructor
for a class. Constructor names can be either ClassName or
ClassName.identifier. For example:

Objects have members consisting of functions and data (methods and
instance variables, respectively). When you call a method, you invoke
it on an object: the method has access to that object’s functions and
data.

If you initialize an instance variable where it is declared (instead of
in a constructor or method), the value is set when the instance is
created, which is before the constructor and its initializer list
execute.

Constructors

Declare a constructor by creating a function with the same name as its
class (plus, optionally, an additional identifier as described in
Named constructors).
The most common form of constructor, the generative constructor, creates
a new instance of a class:

Remember that constructors are not inherited, which means that a
superclass’s named constructor is not inherited by a subclass. If you
want a subclass to be created with a named constructor defined in the
superclass, you must implement that constructor in the subclass.

Invoking a non-default superclass constructor

By default, a constructor in a subclass calls the superclass’s unnamed,
no-argument constructor.
The superclass’s constructor is called at the beginning of the
constructor body. If an initializer list
is also being used, it executes before the superclass is called.
In summary, the order of execution is as follows:

initializer list

superclass’s no-arg constructor

main class’s no-arg constructor

If the superclass doesn’t have an unnamed, no-argument constructor,
then you must manually call one of the constructors in the
superclass. Specify the superclass constructor after a colon (:), just
before the constructor body (if any).

In the following example, the constructor for the Employee class
calls the named constructor for its superclass, Person.
Click the run button ( ) to execute the code.

Because the arguments to the superclass constructor are evaluated before
invoking the constructor, an argument can be an expression such as a
function call:

Factory constructors

Use the factory keyword when implementing a constructor that doesn’t
always create a new instance of its class. For example, a factory
constructor might return an instance from a cache, or it might return an
instance of a subtype.

The following example demonstrates a factory constructor returning
objects from a cache:

Getters and setters

Getters and setters are special methods that provide read and write
access to an object’s properties. Recall that each instance variable has
an implicit getter, plus a setter if appropriate. You can create
additional properties by implementing getters and setters, using the
get and set keywords:

With getters and setters, you can start with instance variables, later
wrapping them with methods, all without changing client code.

Note:
Operators such as increment (++) work in the expected way, whether or
not a getter is explicitly defined. To avoid any unexpected side
effects, the operator calls the getter exactly once, saving its value
in a temporary variable.

Abstract methods

Instance, getter, and setter methods can be abstract, defining an
interface but leaving its implementation up to other classes. To make a
method abstract, use a semicolon (;) instead of a method body:

Abstract classes

Use the abstract modifier to define an abstract class—a class that
can’t be instantiated. Abstract classes are useful for defining
interfaces, often with some implementation. If you want your abstract
class to appear to be instantiable, define a factory
constructor.

Abstract classes often have abstract methods.
Here’s an example of declaring an abstract class that has an abstract
method:

Implicit interfaces

Every class implicitly defines an interface containing all the instance
members of the class and of any interfaces it implements. If you want to
create a class A that supports class B’s API without inheriting B’s
implementation, class A should implement the B interface.

A class implements one or more interfaces by declaring them in an
implements clause and then providing the APIs required by the
interfaces. For example:

// A person. The implicit interface contains greet().
class Person {
// In the interface, but visible only in this library.
final _name;
// Not in the interface, since this is a constructor.
Person(this._name);
// In the interface.
String greet(who) => 'Hello, $who. I am $_name.';
}
// An implementation of the Person interface.
class Imposter implements Person {
// We have to define this, but we don't use it.
final _name = "";
String greet(who) => 'Hi $who. Do you know who I am?';
}
greetBob(Person person) => person.greet('bob');
main() {
print(greetBob(new Person('kathy')));
print(greetBob(new Imposter()));
}

Here’s an example of specifying that a class implements multiple
interfaces:

class Point implements Comparable, Location {
// ...
}

Extending a class

Use extends to create a subclass, and super to refer to the
superclass:

Note:
Consider using top-level functions, instead of static methods, for
common or widely used utilities and functionality.

You can use static methods as compile-time constants. For example, you
can pass a static method as a parameter to a constant constructor.

Generics

If you look at the API documentation for the basic array type,
List,
you’ll see that the
type is actually List<E>. The <…> notation marks List as a
generic (or parameterized) type—a type that has formal type
parameters. By convention, type variables have single-letter names, such
as E, T, S, K, and V.

Why use generics?

Because types are optional in Fart, you never have to use generics.
You might want to, though, for the same reason you might want to use
other types in your code: types (generic or not) let you document and
annotate your code, making your intent clearer.

For example, if you intend for a list to contain only strings, you can
declare it as List<String> (read that as “list of string”). That way
you, your fellow programmers, and your tools (such as your IDE and
the Fart VM in checked mode) can detect that assigning a non-string to
the list is probably a mistake. Here’s an example:

Another reason for using generics is to reduce code duplication.
Generics let you share a single interface and implementation between
many types, while still taking advantage of checked mode and static
analysis early warnings. For example, say you create an interface for
caching an object:

In this code, T is the stand-in type. It’s a placeholder that you can
think of as a type that a developer will define later.

Using collection literals

List and map literals can be parameterized. Parameterized literals are
just like the literals you’ve already seen, except that you add
<type> (for lists) or
<keyType, valueType> (for maps)
before the opening bracket. You might use
parameterized literals when you want type warnings in checked mode. Here
is example of using typed literals:

However, the is expression checks the type of the collection
only—not of the objects inside it. In production mode, a List<String>
might have some non-string items in it. The solution is to either check
each item’s type or wrap item-manipulation code in an exception handler
(see Exceptions).

Note:
In contrast, generics in Java use erasure, which means that generic
type parameters are removed at runtime. In Java, you can test whether
an object is a List, but you can’t test whether it’s a List<String>.

Restricting the parameterized type

When implementing a generic type,
you might want to limit the types of its parameters.
You can do this using extends.

// T must be SomeBaseClass or one of its descendants.
class Foo<T extends SomeBaseClass> {...}
class Extender extends SomeBaseClass {...}
void main() {
// It's OK to use SomeBaseClass or any of its subclasses inside <>.
var someBaseClassFoo = new Foo<SomeBaseClass>();
var extenderFoo = new Foo<Extender>();
// It's also OK to use no <> at all.
var foo = new Foo();
// Specifying any non-SomeBaseClass type results in a warning and, in
// checked mode, a runtime error.
// var objectFoo = new Foo<Object>();
}

Using generic methods

Initially, Fart’s generic support was limited to classes.
A newer syntax, called generic methods, allows type arguments on methods and functions:

Libraries and visibility

The import and library directives can help you create a
modular and shareable code base. Libraries not only provide APIs, but
are a unit of privacy: identifiers that start with an underscore (_)
are visible only inside the library. Every Fart app is a library, even
if it doesn’t use a library directive.

Using libraries

Use import to specify how a namespace from one library is used in the
scope of another library.

For example, Fart web apps generally use the
dart:html
library, which they can import like this:

import 'dart:html';

The only required argument to import is a URI specifying the
library.
For built-in libraries, the URI has the special dart: scheme.
For other libraries, you can use a file system path or the package:
scheme. The package: scheme specifies libraries provided by a package
manager such as the pub tool. For example:

Note:URI stands for uniform resource identifier.
URLs (uniform resource locators) are a common kind of URI.

Specifying a library prefix

If you import two libraries that have conflicting identifiers, then you
can specify a prefix for one or both libraries. For example, if library1
and library2 both have an Element class, then you might have code like
this:

Implementing libraries

Asynchrony support

Fart has several language features
to support asynchronous programming.
The most commonly used of these features are
async functions and await expressions.

Fart libraries are full of functions that
return Future or Stream objects.
These functions are asynchronous:
they return after setting up
a possibly time-consuming operation
(such as I/O),
without waiting for that operation to complete.

When you need to use a value represented by a Future,
you have two options:

Declaring async functions

An async function is a function whose body is marked with
the async modifier.
Although an async function might perform time-consuming operations,
it returns immediately—before
any of its body executes.

checkVersion() async {
// ...
}
lookUpVersion() async => /* ... */;

Adding the async keyword to a function makes it return a Future.
For example, consider this synchronous function,
which returns a String:

String lookUpVersionSync() => '1.0.0';

If you change it to be an async function—for example,
because a future implementation will be time consuming—the
returned value is a Future:

Future<String> lookUpVersion() async => '1.0.0';

Note that the function’s body doesn’t need to use the Future API.
Fart creates the Future object if necessary.

Using await expressions with Futures

An await expression has the following form:

awaitexpression

You can use await multiple times in an async function.
For example, the following code waits three times
for the results of functions:

In await expression,
the value of expression is usually a Future;
if it isn’t, then the value is automatically wrapped in a Future.
This Future object indicates a promise to return an object.
The value of await expression is that returned object.
The await expression makes execution pause until that object is available.

If await doesn’t work, make sure it’s in an async function.
For example, to use await in your app’s main() function,
the body of main() must be marked as async:

Callable classes

To allow your Fart class to be called like a function,
implement the call() method.

In the following example, the WannabeFunction class defines
a call() function that takes three strings and concatenates them,
separating each with a space, and appending an exclamation.
Click the run button ( ) to execute the code.

Isolates

Modern web browsers, even on mobile platforms, run on multi-core CPUs.
To take advantage of all those cores, developers traditionally use
shared-memory threads running concurrently. However, shared-state
concurrency is error prone and can lead to complicated code.

Instead of threads, all Fart code runs inside of isolates. Each
isolate has its own memory heap, ensuring that no isolate’s state is
accessible from any other isolate.

Typedefs

In Fart, functions are objects, just like strings and numbers are
objects. A typedef, or function-type alias, gives a function type a
name that you can use when declaring fields and return types. A typedef
retains type information when a function type is assigned to a variable.

Type information is lost when assigning f to compare. The type of
f is (Object, Object) → int (where → means returns), yet the
type of compare is Function. If we change the code to use explicit
names and retain type information, both developers and tools can use
that information.

Metadata

Use metadata to give additional information about your code. A metadata
annotation begins with the character @, followed by either a reference
to a compile-time constant (such as deprecated) or a call to a
constant constructor.

Three annotations are available to all Fart code: @deprecated,
@override, and @proxy. For examples of using @override and
@proxy, see Extending a class.
Here’s an example of using the @deprecated
annotation:

Metadata can appear before a library, class, typedef, type parameter,
constructor, factory, function, field, parameter, or variable
declaration and before an import or export directive. You can
retrieve metadata at runtime using reflection.

Multi-line comments

A multi-line comment begins with /* and ends with */. Everything
between /* and */ is ignored by the Fart compiler (unless the
comment is a documentation comment; see the next section). Multi-line
comments can nest.

Documentation comments

Documentation comments are multi-line or single-line comments that begin
with /// or /**. Using /// on consecutive lines has the same
effect as a multi-line doc comment.

Inside a documentation comment, the Fart compiler ignores all text
unless it is enclosed in brackets. Using brackets, you can refer to
classes, methods, fields, top-level variables, functions, and
parameters. The names in brackets are resolved in the lexical scope of
the documented program element.

Here is an example of documentation comments with references to other
classes and arguments:

Summary

This page summarized the commonly used features in the Fart language.
More features are being implemented, but we expect that they won’t break
existing code. For more information, see the Fart Language
Specification and
Effective Fart.