Dart Basics
Dart Basics
You’re looking to get started with Flutter development, but have only just found out
that Flutter uses the Dart programming language? This tutorial will introduce you to
some Dart basics so you can get up and running with the language for Flutter
development.
Dart was released by Google in 2011 and was initially designed as a replacement for
JavaScript. Since then, the release of the Flutter SDK for iOS, Android, and web
development has put a new spotlight on the Dart language. The most recent version
of Dart at the time of this recording is 2.4.
Dart has many similarities to other languages you may already be familiar with, such
as Java, C#, Swift, and Kotlin. Dart has the following language characteristics:
▪ Statically typed
▪ Type inference
▪ String expressions
▪ Multi-paradigm including OOP and functional
▪ Can mimic dynamic types using dynamic
In addition to its use for mobile and web development, Flutter is the development kit
for Fuchsia, an experimental operating system under development at Google.
Down in the lower bottom right, there’s a checkbox to show some more panels related to
using Dart for web programming, and some text showing the current version of Dart being
used in DartPad.
If you prefer, you can install the Dart SDK locally on your machine. One way to do so is
to install the Flutter SDK. Installing flutter will also install the Dart SDK.
You can also just install the Dart SDK directly by visiting here.
Core Concepts
Dart programs begin with a call to the `main` function, and the syntax for `main` looks very
similar to the syntax for `main` in other languages like C, Swift, or Kotlin.
Clear out all the code in the default DartPad, and add a `main` function to the editor:
void main() {
The main function is preceded by a return type, which in Dart is void , meaning
The main function is preceded by a return type, which in Dart is void , meaning nothing is
returned. The parentheses after main indicate that this is a function definition, and the curly
braces contain the body of the function. Inside main , you add the Dart code for your
program.
The first thing we’ll add to main is a variable assignment statement. Variables hold the data
that your program will work on. You can think of a variable like a box in your computer’s
memory that holds a value. Each box has a name, the name for the variable. You use
the var keyword in Dart to denote a variable.
Like C and Java, each Dart statement ends in a semicolon. You’ve created a myAge variable
set it equal to 35.
You can use the built-in print function in Dart to print the variable to the console, so add
that call after the variable:
print(myAge); // 35
Click the Run button in DartPad to run the code, and you’ll see the variable printed out in the
console on the upper right.
Comments in Dart look just like those in C in other languages: text either following // on a
line, or text within /* … */ blocks.
// This is a comment.
/*
And so is this.
*/
If you put the cursor in the editor over the myAge name, you’ll see in the lower right panel
that Dart has inferred that myAge is an int variable, thanks to being initialized with the
integer value 35. Like Swift and Kotlin, Dart uses type inference to attempt to figure out the
type of your date if you do not specify it directly.
An alternative to using type inference is to replace the var keyword with the specific type
you want to use:
print(yourAge); // 27
Similar to many languages such as C, Java, Swift, and Kotlin, Dart is statically typed. That
means that each variable in Dart has a type that must be known when the code is compiled,
and the type of the variable cannot change when the program is run.
This contrasts with languages like Python and Javascript that are dynamically typed,
meaning variables can hold different kinds of data when being run, and the type does not
need to be known when the code is compiled.
Dart uses int for integers, double for floating points, and bool for booleans. int s
and double s are both derived from a type named num . You use the String type to represent
sequences of characters. Dart also has a keyword dynamic which lets you mimic dynamic
typing in the statically typed Dart.
You can also use type inference for types other than int . Enter a variable pi equal to 3.14
like so:
var pi = 3.14;
print(pi); // 3.14
pi is inferred to be a double since you used a floating-point value to initialize it. You can
see that in the Dart info panel
You can also just use double as the type instead of var :
double c = 299792458;
print(c); // 299792458
In this case, you’ve initialized c , the symbol for the speed of light, with an int , but because
you specified the type as double, c is in fact a double . Dart will convert the int to
a double in order to initialize c . So unlike Swift, Dart has implicit type-conversion.
If you use the dynamic keyword instead of var , you get what is effectively a dynamically-
typed variable:
dynamic numberOfKittens;
You can set numberOfKittens to a String using quotes (see below for more on
the String type)
numberOfKittens has a type, as it must since Dart has static typing. But that type
is dynamic , which means you can assign other values with other types to it. So you can
assign an int value below your print statement.
numberOfKittens = 0;
print(numberOfKittens); // 0
Or if you have a kitten in Schrödinger’s box, you could assign a double value:
numberOfKittens = 0.5;
print(numberOfKittens); // 0.5
Go ahead and click Run to see the three different values for numberOfKittens all printed
out in the console. In each case, the type of numberOfKittens remains dynamic , even
though the variable itself holds values of different types.
The bool type is used to hold values of either true or false.
print(areThereKittens); // false
But, if you look inside the Schrödinger box, you may switch to having a real live kitten:
numberOfKittens = 1;
areThereKittens = true;
print(areThereKittens); // true
Run the code again to see your boolean values in the console. It’s a good thing you looked in
the box!
Operators
Dart has all the usual operators you’re familiar with from other languages like C, Swift, and
Kotlin.
Dart also allows for operator overloading like C++ and Kotlin, but that’s beyond the scope
of this tutorial.
The arithmetic operators work just liked you’d expect. Add a bunch of operations to your
DartPad:
print(40 + 2); // 42
print(44 - 2); // 42
print(21 * 2); // 42
print(84 / 2); // 42
print(atltuae); // 42
Dart converts the int to a double prior to the operation, so that the resulting variable is
inferred to be a double .
print(atltuae++); // 42
print(--atltuae); // 42
Because the use of increment is postfix, 42 is printed before the increment occurs. The
decrement is prefix, so 43 is decremented to 42 and then the value 42 is printed.
Dart has the typical comparison operators like less than and greater than or equal to.
atltuae += 1; print(atltuae); // 43
atltuae -= 1; print(atltuae); // 42
atltuae *= 2; print(atltuae); // 84
atltuae /= 2; print(atltuae); // 42
The logical operators such as && for and and || for or look just like those from other
languages.
And the negation operator is the exclamation mark, turning false to true and true to false.
Strings
The Dart string type is String . Strings are expressed in Dart using text surrounded
by either single or double quotes.
Like for the other types we've seen, you can use either var and type inference or String to
create a string variable:
Similar to languages like Kotlin and Swift, you can embed values and expressions inside
strings to create new strings, using the dollar sign symbol $.
You can combine adjacent strings, for example, long strings that go multiple lines, simply by
placing the strings next to one another or on separate lines:
print(quote);
// If you can't explain it simply
Here in the first string, you used single quotes and so used an escape sequence \' to embed a
quotation mark for can't into the string. The escape sequences used in Dart are similar to
those used in other C-like languages, for example, \n for a newline.
Since you used double-quotes to delimit the second string, you did not need an escape
sequence for the single quote on don't .
You can use triple quotes to have a string run multiple lines and preserve formatting:
print(model);
If you need to have escape sequences shown within the string, you can use raw strings,
which are prefixed by r.
print(rawString);
Immutability
Dart has the keywords const and final for values that don't change. const is used for
values that are known at compile-time, final is used for values that don't have to be known
at compile-time but cannot be re-assigned after being initialized. final acts like val in
Kotlin or let in Swift.
You can use const and final in place of var and let type inference determine the type:
print(speedOfLight); // 299792458
So speedOfLight is inferred to be an int , as you can see in the info panel of DartPad.
final means immutable, and final values cannot be re-assigned. You can also explicitly
state the type with either final or const :
Nullability
For any variable, no matter the type, if you do not initialize the variable, the variable will be
given the value null , which means nothing is stored in the variable.
This is in contrast to languages like Swift and Kotlin, for which you have to explicitly declare
a variable as being nullable (aka optional in Swift). Default types in those languages are non-
nullable.
It turns out that all Dart types, even basic types like int and double , are derived from a type
named Object . And if you don't initialize an object, it takes on a null value.
You'll see here some ways to handle null values safely in Dart, but it does not go quite as far
as optionals in Swift or nullables in Kotlin.
Create three variables of different types and then immediately print them.
int age;
double height;
String err;
print(age); // null
print(height); // null
print(err); // null
Dart has some null-aware operators you can use for working with null values.
The double-question mark operator ?? is like the "Elvis operator" in Kotlin: it will return the
left-hand operand if it's not-null, otherwise the right-hand value:
print(error); // No error
print(err); // No error
Since you just made error non-null with a value "No error", the err value now picks up that
non-null value on this assignment.
There's also an operator ?. that protects you from accessing properties on null objects. It will
return null if the object itself is null. Otherwise, it returns the value of the property on the
right-hand side:
print(age?.isEven); // null
If you tried just age.isEven and age was null , you'd get an Uncaught exception.
Control Flow
Control flow lets you dictate that certain lines of code are executed, skipped over, or
repeated. Control flow is handled in Dart with conditionals and loops.
Conditionals
The most basic form of control flow is deciding whether to execute or skip over certain parts
of your code, depending on conditions that occur as your program runs. The language
construct for handling conditions is the if / else statement. if / else in Dart looks nearly
identical to the use in other C-like languages.
You can use an if statement to check whether the animal is a cat or dog, and run some
corresponding code if so.
Here you've used the equality and or operators to create a bool value inside the condition for
the if statement.
You can use an else clause to run alternative code if the condition is false:
} else {
} else {
You can have as many else if branches in between if and else as needed.
While Loops
Loops let you repeat code a certain number of times or based on certain conditions. The latter
are handled by while loops.
There are two forms of while loop in Dart, while and do-while . The difference is that
for while , the loop condition is before the code block, and in do-while the condition is
after. So for do-while , the code block is guaranteed to run at least one time.
var i = 1;
You can use a while loop to print i while incrementing it, and set the condition to be
that i is less than 10:
while (i < 10) {
print(i);
i++;
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
Run the code and you see the numbers 1 to 9 printed out by the while loop.
i = 1;
do {
print(i);
++i;
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
The results here are the same as before, just this time, the loop body ran once before the loop
exit condition was checked.
Dart has the usual continue and break keywords for use in loops and
elsewhere. continue will skip remaining code inside a loop and immediately go to the next
iteration. break stops the loop and continues execution after the body of the loop.
You must be careful when using continue in your code. For example, if you take the do-
while loop from above, and say you want to continue when i is equal to 5, that could result
in an infinite loop that just keeps running, depending in where you place
the continue statement:
do {
print(i);
if (i == 5) {
continue;
++i;
// 1
// 2
// 3
// 4
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// 5
// ...
The infinite loop occurs since once i is 5, you never increment i , and the condition always
stays true.
If you run this in DartPad, the infinite loop will cause the browser to hang. Instead
use break , so that the loop will end after i reaches 5:
do {
print(i);
if (i == 5) {
break;
++i;
// 1
// 2
// 3
// 4
// 5
Run the code now and see that the loop ends after 5 iterations.
For Loops
The loops that loop a pre-determined number of times are for loops in Dart, which once again
are very similar to those from other languages.
Dart has both a C-like form of a for loop, with an initialization, loop condition, and an action,
as well a for-in loop for iterating over a collection of objects. In the first form, the
initialization runs before the first loop iteration. The condition is checked on entering each
iteration, and the action is run before starting the next iteration.
For the for-in form, a variable is set to each element in a collection of Dart objects for each
subsequent iteration of the loop. Let's say you want to sum up the values of the first 10
integers.
var sum = 0;
Then use a for loop in which you initialize a loop counter i to 1, check that i is less than or
equal to 10, and increment i after every loop. Inside the loop use a compound assignment to
add i to the running sum:
sum += i;
An example of a Dart collection is a simple list of numbers made with square brackets:
print(number);
}
// 1
// 2
// 3
// 4
The variable number takes on the value of each element of numbers as you iterate in the
loop.
Lists like numbers also have a function you can call on them named forEach , which
simplifies the previous loop down to one line:
// 1
// 2
// 3
// 4
Here you've used an anonymous function and arrow syntax, both of which you'll see later
on in the section on Functions.
Finally, like while loops, for loops can also use continue and break to control flow within
the loop. For example, if you want to skip printing the number 3, you can use
a continue statement in the for - in loop:
if (number == 3) {
continue;
print(number);
// 1
// 2
// 4
switch and enum
Dart also has support for a switch statement and enumerations using enum . Consult the Dart
documentation for more on both. Like most of the rest of the Dart constructs you've seen,
they work similarly to how they work in other languages like C and Java.
Functions
Functions let you package multiple related lines of code into a single body that you can
summon to avoid repeating those lines of code throughout your Dart application:
A function consists of a return type, a function name, a parameter list in parentheses, and
then a function body enclosed in braces. The code you're turning into the function goes
inside the braces. When you call the function, you pass in arguments that match the types of
the parameters of the function.
Note: Specifying a return type on functions is optional. If you leave off the return type, values
returned from the function will either have an inferred type, or be dynamic if the type cannot be
inferred. That allows you to return values of different types from the function. Usually you'll want to
avoid this and instead specify a single return type from functions.
Typically, functions are defined either outside other functions or inside Dart classes, but you
can also nest Dart functions in one another. For example, you can add the functions in this
section inside main .
Write a new function in DartPad that will just check to see if a given string is banana.
The function uses return to return a bool value determined by the argument passed to the
function. This function will always return the same value for any given input. If a function
does not need to return a value, you can set the return type to void , such as for
the main function.
You can call the function by passing in a string. Then you might pass the result of that call
onto print :
print(isBanana(fruit)); // false
You can change the argument passed to functions, and call them again with a new argument:
fruit = 'banana';
print(isBanana(fruit)); // true
The result of calling the function depends entirely on the arguments passed in.
Optional Parameters
If a parameter to a function is optional, you can surround it with square brackets:
If an optional parameter is not included in the function call, the value used is null for the
parameter inside the function body.
Then you can call the function with or without the optional parameter:
print(fullName("Joe", "Howard"));
// Joe Howard
Then you can pass in arguments in a different order by supplying the parameter names with a
colon:
Like for optional parameters, arguments with optional names do not need to be added to a
function call, and the corresponding parameters will be given the value null in the
function.
Default Values
You can also assign default values to one or more parameters using equals:
You can then leave off the parameters with default values when calling the function.
First-Class Functions
Dart has support for what are called first-class functions. The term means that functions are
treated like any other data type, that is, they can be assigned to variables, passed as
arguments, and returned from other functions.
You can use the Function type to specify that a parameter named op is a function itself:
return op(value);
int square(int n) {
return n * n;
print(applyTo(3, square)); // 9
var op = square;
Then you can call the function on the variable as if it were an alias for the original function:
print(op(5)); // 25
You'll see more about returning functions from other functions a bit later.
return a * b;
};
Since multiply now holds an anonymous function, you can call it as you would any other
function:
print(multiply(14, 3)); // 42
You've seen a preview earlier of lists and the forEach function. forEach is a great example
of using an anonymous function.
You can call forEach on the list and pass in an anonymous function that triples an element
and prints out the tripled value:
numbers.forEach((number) {
print(tripled);
// 3
// 6
// 9
});
};
This is useful for generating functions with a given behavior but with varying input parameter
values. So the return value here is a function that takes one num parameter and multiplies it
by the multiple used to generate the function.
print(triple(6)); // 18
print(triple(14.0)); // 42
Anonymous functions in Dart act as closures, which means they "close-over" variables
defined outside of themselves. For example, the return value of
the applyMultiplier function above is a closure that has access to the multiplier variable
defined elsewhere, in that case in the parameter list for applyMultiplier itself.
Arrow Syntax
When a Dart function, either named or anonymous, consists of just one line of code, you can
reduce the function body using the Dart arrow syntax.
In the example just above using forEach , you cannot use arrow syntax, since the body of the
function you're passing to forEach has more than one line of code.
You can download all the code for this tutorial by clicking the Download Materials button at
the top or bottom of the page. You can either paste the code in the main.dart file into
DartPad or use the Dart SDK to run the file.
As mentioned in the introduction, you can go beyond the basics and learn more
about Object-Oriented Programming in Dart as well as Dart collection types such as lists,
sets, and maps, in our course Programming in Dart - Fundamentals, on which this short
tutorial is based.
Check out the official Dart documentation to learn about intermediate and advanced parts of
Dart:
We'll be covering these and other Dart topics in future tutorials and video courses.
I hope you enjoyed this brief introduction to Dart basics. Please write to us in the forums
below if you have questions or comments!