Dart Playbook
A new way of learning Dart language. Don't just read but try it out yourself.

A cheat class to learn the Dart programming language for Flutter enthusiasts.
The embedded editors in this codelab have partially completed code snippets. You can use these editors to test your knowledge by completing the code and clicking the Run button. To run the code formatter (dartfmt), click Format. The Reset button erases your work and restores the editor to its original state.
1. Hello Flutter
This is our first program. Let's see how we can print "Hello, World Flutter". Try changing it to your name and then click on the Run button. For eg: Hello Pawan
void main() {
print('Hello, Flutter');
}
Wow, nice start. You just printed your name in the console 🥳.
2. Functions
Function is nothing but a piece of code which does something. For eg: When you say call someone then we can use a function named call() and write some code inside it to make it work.
A basic Dart program
// Define a function.
void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// This is where the app starts executing.
void main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}
Here’s what this program uses that applies to all (or almost all) Dart apps:
// This is a comment.
A single-line comment. Dart also supports multi-line and document comments.
void
A special type that indicates a value that’s never used.
Functions like printInteger()
and main()
that don’t explicitly return a value have the void
return type.
int
Another type, indicating an integer. Some additional built-in types are String
, List
, 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.
main()
The special, required, top-level function where app execution starts.
var
A way to declare a variable without specifying its type.
Now change the function name to "showANumber()" and print "The lottery number is 25" and then Run it.
// Define a function.
void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// This is where the app starts executing.
void main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}
3. Variables
Variable is something which holds a value and that value can change or vary. So that's why it is called a variable.
For eg: var name = "Pawan";
dynamic name = 'Pawan';
Another option is to explicitly declare the type that would be inferred:
String name = 'Pawan';
var
can be of different types as mentioned below.
Built-in types
The Dart language has special support for the following types:
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
Try changing my values with yours like your name, height, gender and country etc, And Run
it.
void main() {
//This is for declaring a number
int age = 25;
//This is a string
String name = 'Pawan Kumar';
//This is boolean which can be true or false
bool isMale = true;
//This is a double which holds floating value
double height = 170.5;
//Common variable when you don't want to specify it's type.
var country = 'India';
print(age);
print(name);
print(isMale);
print(height);
print(country);
}
Well done, you are learning it fast ⚡️.
Final and const
If you never want to change a variable, use final
or const
, either instead of var
or in addition to a type.
The main difference between final and const is that a final object can be modified but a const can never.
Play with this program and follow the instruction to understand it better.
void main() {
//Final types
// A constant value like math's pi
const pi = 3.14;
// A final value which is not supposed to change like someone's gender
final gender = 'Male';
print(pi);
print(gender);
// But both have a minor difference which we can see below.
// Try changing it from final to const & see if that works.
final List myList = [1,2,3];
print(myList[myList.length-1]);
myList.add(10);
print(myList[myList.length-1]);
}
When you tried const with myList, it showed an error right? That is actually expected because as I told you that const object cannot be modified.
4. Functions in detail
A function can have any number of required positional parameters. These can be followed either by named parameters or by optional positional parameters (but not both).
Named parameters
Named parameters are optional unless they’re specifically marked as required.
When calling a function, you can specify named parameters using paramName: value
. For example:
enableAuthentication(touchID: true, faceID: false);
When defining a function, use {param1, param2, …}
to specify named parameters:
/// Sets the [bold] and [hidden] flags ...
void enableAuthentication({bool touchID, bool faceID}) {...}
const Scrollbar({Key key, @required Widget child})
//To use the @required annotation, depend on the meta package and import package:meta/meta.dart.
Optional positional parameters
Wrapping a set of function parameters in []
marks them as optional positional parameters:
void main(){
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
}
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
.
Here’s an example of setting default values for named parameters:
/// Sets the [touchID] and [faceID] flags ...
void enableAuthentication({bool touchID = false, bool faceID = false}) {...}
// touchID will be true; faceID will be false.
enableAuthentication(touchID: true);
To understand functions in detail, try playing with this piece of code because until you practice, you won't understand it well. So it's very crucial to play with it.
void main() {
int num1 = 20;
int num2 = 5;
printNumber(num1, num2);
//Call function 2 (We are looping the data here)
var list = [1, 2, 3];
list.forEach(printElement);
//Call function 3
var add2 = makeAdder(2); // Create a function that adds 2.
var add4 = makeAdder(4); // Create a function that adds 4.
assert(add2(3) == 5);
assert(add4(3) == 7);
//Call function 4
var output1 = say("Pawan", "Hi");
print(output1);
var output2 = say("Pawan", "Hi", "Pixel");
print(output2);
//Call function 5
var output3 = sayAgain("PK", msg : "Hello");
print(output3);
}
//function 1
void printNumber(num number1, number2) {
print(number1 + number2);
}
//function 2
printElement(element) {
print(element);
}
//function 3
Function makeAdder(num n) {
return (num i) => n + i;
}
//function 4
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
//function 4
String sayAgain(String from, {String msg, String device = "Galaxy"}) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
Functions can also give back some value or another function and we call/represent with return
keyword.
All functions return a value. If no return value is specified, the statement return null;
is implicitly appended to the function body.
bool isDog(int legs) {
return legs==4;
}
This function returns true
if the legs are 4 otherwise it returns false
5. Operators
Dart supports the operators shown in the following table.

Let's take a look at some common ones.
Arithmetic Operators:
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Type test operators
The as
(Typecast), is
(True if the object has the specified type), and is!
(False if the object has the specified type) operators are handy for checking types at runtime.
Example:
(emp as Person).firstName = 'Pawan';
if (emp is Person) {
// Type check
emp.firstName = 'Pawan';
}
Play with all the operators to learn more about them. Experimenting is important.
void main() {
var z = 5;
var a, b;
//Play with prefix and postfix increment and decrement operators
a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1
a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0
a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1
a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0
//Play with Equality and relational operators
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;
print(z + z);
print(z / z);
print(z * z);
print(z - z);
print(z = z);
print(z != z);
print(z % z);
print(z < z);
print(z > z);
print(z >= z);
print(z <= z);
print(z | z);
}
6. Controls
Conditional expressions
Dart has two operators that let you concisely evaluate expressions that might otherwise require if-else statements:
condition ? expr1 : expr2
If condition is true, evaluates expr1 (and returns its value); otherwise, evaluates and returns the value of expr2.
expr1 ?? expr2
If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.
Example:
var title = isPublic ? 'public' : 'private';
// All of the below produces the same result
//Better version
String playerName(String name) => name ?? 'Guest';
// Slightly longer version uses ?: operator.
String playerName(String name) => name != null ? name : 'Guest';
// Very long version uses if-else statement.
String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
Cascade notation (..)
Cascades (..
) allow you to make a sequence of operations on the same object.
Example:
Version 1
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
can be replaced with Version 2
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
Control flow statements
Control flow generally have some decision making involve. Below example can help you in understanding the control flow in dart.
//Control Flow
void main() {
// if else
bool hasChargerInTheBox = true;
if (hasChargerInTheBox) {
print('Non iPhone');
} else {
print('iPhone');
}
//For loop
var listData = [1, 2, 3, 4, 5];
for (var x in listData) {
print(x);
}
//While and Do-While
int number = 0;
do {
if (number % 2 == 0) {
print(number);
}
number++;
} while (number < 10);
//Switch Case
var command = 'OPEN';
switch (command) {
case 'CLOSED':
print('Please open the ticket');
break;
case 'PENDING':
print('Ticket will be opened soon');
break;
case 'OPEN':
print('Ticket is already opened');
break;
case 'DENIED':
print('You cannot open the ticket');
}
}
7. Asserts
During development, use an assert statement — assert(condition, optionalMessage)
; — to disrupt normal execution if a boolean condition is false.
It can be used while developing. Although with the support of null-safety it won't be needed anymore.
void main() {
String text = 'I hope you are enjoying codepur.';
assert(text != null);
}
8. Exceptions
Your Dart 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.
Some of the examples can be tested here:
void main() {
int x = 11;
int y = 0;
int res;
try {
res = x ~/ y;
} on IntegerDivisionByZeroException {
print('Cannot divide by zero');
}
exception();
exceptionWithFinaly();
}
// Try catch with exception
exception() {
int x = 10;
int y = 0;
int res;
try {
res = x ~/ y;
} catch (e) {
print(e);
}
}
// With finally
exceptionWithFinally() {
int x = 9;
int y = 0;
int res;
try {
res = x ~/ y;
} on IntegerDivisionByZeroException {
print('Cannot divide by zero');
} finally {
print('Finally block executed');
}
}
9. Classes and Objects
Dart 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.
You can consider classes as a blueprint. And objects are made out of those blueprints.
// Structure of Class in Dart
class className {
<fields>
<getters/setters>
<constructors>
<functions>
}
Fields/Instance variables − A field is any variable declared in a class. Fields represent data pertaining to objects.
Setters and Getters − Allows the program to initialize and retrieve the values of the fields of a class. A default getter/ setter is associated with every class. However, the default ones can be overridden by explicitly defining a setter/ getter.
Constructors − responsible for allocating memory for the objects of the class.
Methods − Methods represent actions an object can take. They are also at times referred to as functions.
void main() {
Car c = Car();
c.desciption();
}
class Car {
// fields
String engine = "B1001";
String brand = "Ferari";
String owner = "Zidniryi";
int yearProd = 2021;
bool isColorRed = true;
// method
void desciption() {
print(engine);
print(brand);
print(owner);
print(yearProd);
print(isColorRed);
}
}
10. Regex
A regular expression (regex or regexp for short) is
- a special text string for describing a search pattern.
- You can think of regular expressions as wildcards on steroids.
void main() {
RegExp re = new RegExp(r'(\w+)');
String str1 = "one two three";
print('Has match: ${re.hasMatch(str1)}');
// First match
Match firstMatch = re.firstMatch(str1);
print('First match: ${str1.substring(firstMatch.start, firstMatch.end)}');
// Iterate all matches
Iterable matches = re.allMatches(str1);
matches.forEach((match) {
print(str1.substring(match.start, match.end));
});
}
11. Lists
Perhaps the most common collection in nearly every programming language is the array, or ordered group of objects. In Dart, arrays are List objects, so most people just call them lists.
void main() {
// Using a List constructor.
// Or simply use a list literal.
var fruits = ['apples', 'oranges'];
// Add to a list.
fruits.add('kiwis');
print(fruits);
print(fruits.length);
// Add multiple items to a list.
fruits.addAll(['grapes', 'bananas']);
print(fruits);
// Get the list length.
assert(fruits.length == 5);
// Remove a single item.
var appleIndex = fruits.indexOf('apples');
fruits.removeAt(appleIndex);
assert(fruits.length == 4);
print(fruits);
// Check with isEmpty or isNonEmpty rather than length
assert(fruits.isEmpty == false);
// Remove all elements from a list.
fruits.clear();
assert(fruits.length == 0);
print(fruits);
}
12. Mixins
Mixins are a way of reusing a class’s code in multiple class hierarchies.
To use a mixin, use the with
keyword followed by one or more mixin names. The following example shows two classes that use mixins:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
13. Asynchronous Future
Dart 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.
The async
and await
keywords support asynchronous programming, letting you write asynchronous code that looks similar to synchronous code.
Future<void> getUser() {
return Future.delayed(Duration(seconds: 3), () => print('User Data'));
}
void main() {
getUser();
print('Fetching user data...');
}
14. Synchronous
Consider a situation like standing in an ATM queue. Only one person can use the ATM at once. That's exactly what synchronous operation is. Others will wait while one task is getting executed.
import 'dart:io';
void main() {
print("Enter your name :");
// Prompt for user input
String name = stdin.readLineSync();
// This is a synchronous method that reads user input
print("Hello ${name}");
print("End of main");
}
15. Using Math Lib
We can many core libraries in our code. One of the common library is dart:math
.
import "dart:math" as math;
void main() {
print(math.pi / 3);
}
}
16. Create a lib
We can create above kind of libraries easily by ourselves.
// Create library
dart_lib(num1, num2) {
print(num1 + num2);
}
// Calling the library
import 'dart_lib.dart';
void main() {
// call that
dart_lib(20, 20);
}
This playbook will keep updating as per latest changes and updates.
Take a full language tour here:

Take a full core library tour here:

If you are a video person, then start your dart journey with the below video.