Dart Reference

Created: Notes on the Dart language

Updated: 03 September 2023

Notes from the The Net Ninja Youtube Series

To get started with Dart you can use DartPad

Hello World

A simple Hello World in dart looks like so:

1
void main() {
2
print("Hello World");
3
}

In Dart we require semicolons and the entrypoint is the main function

Variables

We declare variables like this:

1
int age = 5;
2
print(age);

Some data types are:

  • int
  • String which can use a ' or a "
  • bool
  • dynamic

We can also define variables as dynamic which means that their type can be changed

String interpolation can also be done like so:

1
int age = 5;
2
String name = "John";
3
String person = "My name is $name and I am $age years old";

Functions

Functions make use of the following structure:

1
MyType fName() {
2
...//do stuff
3
4
return thing; //type of MyType
5
}

If a function has a single line we can also make use of an arrow function which looks like this:

1
MyType getThing() => thing;

A function with inputs is defined and used like so:

1
int add(int x, int y) => x + y;

And used as you’d expect:

1
int result = add(1,3);

Functions can also take in optional params, there are two methods for this, named and unnamed params:

1
// unnamed
2
int sumUN(int a, int b, [int c, int d]) => ....
3
4
//named
5
int sumN(int a, int b, {int c, int d}) => ...

The way we call these functions differ

1
// unnamed
2
sumUN(1,2)
3
sumUN(1,2,3)
4
sumUN(1,2,3,4)
5
6
//named
7
sumN(1,2)
8
sumN(1,2, {c: 3})
9
sumN(1,2, {c: 3, d: 4})
10
```
11
12
# Lists
13
14
Lists in Dart are defined using the `[]` notation
15
16
```dart
17
List names = ['john', 'jeff', 'johnny'];

We can also use list methods to work with the list

1
names.add('sally');
2
names.add(12); // not a string
3
4
names.remove('john');

The list as defined above does not have a defined type, usually we want to specify the allowable types (coz obviously). We can set the type using the <T> notation like so:

1
List<String> names = ['john', 'jeff', 'johnny'];

We also have methods available for lists such as the map function which will return an IEnumerable:

1
myList.map((el){
2
// do stuff
3
return el;
4
})

And additionally the toList method which will allow us to convert the above back into a list

1
myList.map((el){
2
// do stuff
3
return el;
4
}).toList()

Classes

Classes are defined using the class keyword, with the properties defined within the class. The new keyword is not needed

1
void main() {
2
Person john = Person("John", 3);
3
john.greet();
4
5
john.setAge(5);
6
7
print(john.getAge());
8
}
9
10
class Person {
11
String name; // public by default
12
int _age; // private if starts with _
13
14
Person(String name, int age){
15
this.name = name;
16
this._age = age;
17
}
18
19
void greet() =>
20
print("Hello, I am " + name);
21
22
void setAge(int newAge) {
23
this._age = newAge;
24
}
25
26
27
int getAge() => this._age;
28
}

Private properties start with _ and cannot be accessed from outside the class

We can also initialize class variables like this:

1
class Person {
2
String name = "Person";
3
int _age = 1;
4
...
5
}

We can use inheritance using the extends keyword:

1
class NotCat {
2
bool isCat = false;
3
String description = "Not a Kitty";
4
5
NotCat(bool isCat){
6
// we don't care
7
}
8
}
9
10
class Person extends NotCat {
11
String name; // public by default
12
int _age; // private if starts with _
13
14
Person(String name, int age): super(false){
15
this.name = name;
16
this._age = age;
17
}
18
}

When using the above we need to be sure to also call the constructor of the base class from the inheriting class using super

Const and Final

A const variable is one that’s value is constant at compile time, a final variable is one that is only assigned to once

In dart we can also define constants using the const and final keywords like so:

1
const int age = 12;
2
final String name= "John";
3
final Person myPerson = Person(name, age);

You can also create constant instances of objects but that requres a const constructor

If we have a class with a constructor but we want to use it as a const constructor, we can do so by using the final keyword for our property, and the below notation for the constructor:

1
class QuoteCard extends StatelessWidget {
2
3
final Quote quote;
4
QuoteCard({this.quote});
5
...
6
}

We can then create an instance of this like so:

1
var myCard = QuoteCard(quote: myQuote)

Maps

Maps are like dictionaries/key-value pairs

To create a map we use the Map data type and the [] accessor:

1
Map person = {
2
"name": "Jeff Smith",
3
"age": 64
4
};
5
6
7
print(person["name"])

This is used in flutter when doing routing for pages

Async

Async code is code that finishes some time after being called but is not blocking. We use a combination of async, await, and Futures

Futures

A function that makes use of a Future that simply does a delay looks like this:

1
void getData(){
2
Future.delayed(Duration(seconds: 3), (){
3
// callback function
4
print("Callback activated")
5
});
6
}

The callback is run when the future completes. This is similar to Promise in JavaScript

We can then call the above function from our initState function. A complete example would be something like this:

1
class _SelectLocationState extends State<SelectLocation> {
2
String name = "FETCHING NAME";
3
4
void getData() {
5
Future.delayed(Duration(seconds: 2), () {
6
// callback function, will run after 2 seconds
7
setState(() {
8
name = "Johnny";
9
});
10
});
11
}
12
13
@override
14
void initState() {
15
super.initState();
16
getData();
17
}
18
19
@override
20
Widget build(BuildContext context) {
21
return Scaffold(
22
backgroundColor: Colors.purple,
23
appBar: AppBar(
24
title: Text("Select Location"),
25
elevation: 0,
26
backgroundColor: Colors.purple,
27
),
28
body: Text(name),
29
);
30
}
31
}

Async/Await

Sometimes however we have some asynchronous code that needs to run sequentially we can make use of async and await

Similar to other languages, Futures (promises) can be awaited within an async function. If we wanted to make our getData function run more sequentially we can do something like this (note we also added async to the function definition):

1
String name = "FETCHING NAME";
2
String bio = "FETCHING BIO";
3
4
void getData() async {
5
String userName = await Future.delayed(Duration(seconds: 2), () {
6
// callback function
7
return "Johnny";
8
});
9
10
String userBio = await Future.delayed(Duration(seconds: 2), () {
11
return "$userName's Bio. Here are more things about $userName";
12
});
13
14
setState(() {
15
name = userName;
16
bio = userBio;
17
});
18
}

Exceptions

To handle exceptions in dart we can use a try-catch:

1
try {
2
// do some stuff
3
} catch(e) {
4
// handle the exception
5
}

We can also use an optional finally

1
try {
2
doStuff();
3
setState(() {
4
hasError = false;
5
});
6
} catch (e) {
7
setState(() {
8
hasError = true;
9
});
10
} finally {
11
setState(() {
12
isLoading = false;
13
});
14
}

Cascade operator

Dart has a cascade operator .. which allows a function to return the instance of the initial object and not the result of a function call:

1
void main() {
2
var person = Person();
3
4
// normal function call returns result
5
print(person.haveBirthday()); // out: 1
6
7
// cascaded function call returns person
8
print(person..haveBirthday()); // out: Instance of 'Person'
9
10
}
11
12
class Person {
13
int age = 0;
14
int haveBirthday() {
15
age ++;
16
return age;
17
}
18
}

Or from the documentation:

“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.”

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

Conditionals

If-Else

1
if (isCar) {
2
print("Car");
3
} else {
4
print("Not Car");
5
}

With multiple conditions:

1
int age = 12;
2
3
if (age > 35) {
4
// do stuff
5
} else if (age > 20) {
6
// do stuff
7
} else if (age > 10) {
8
// do stuff
9
} else {
10
// do stuff
11
}

Ternary

We can use a ternary operator like so:

1
bool isCar = thing == "Car" ? true : false

The ternary operator doesn’t have to return a boolean, it can pretty much be anything

1
String carGoes = thing == "Car" ? "Vroom Vroom" : "Pew Pew Pew"