Dart Lessons
Learn Dart With Simplicity and Clarity
This page is designed to teach Dart in small, practical steps. Each lesson is short, direct, and focused on one concept.
Learning rule for this page:
understand the concept first, then read the code.
Code here is illustration, not the lesson itself.
[Start](#lesson-start) [1](#lesson-1) [2](#lesson-2) [3](#lesson-3) [4](#lesson-4) [5](#lesson-5) [Null](#lesson-null-types) [6](#lesson-6) [Quiz](#lesson-quiz)
Lesson Nav
[Before You Start](#lesson-start) [Who Should Learn Dart?](#lesson-who) [1. First Program](#lesson-1) [2. Variables and Types](#lesson-2) [3. Working With Data Types](#lesson-3) [4. Operators](#lesson-4) [5. If, Else, and Loops](#lesson-5) [Null with Data Types](#lesson-null-types) [6. Functions](#lesson-6) [7. Lists and Maps](#lesson-7) [8. Classes and Objects](#lesson-8) [9. Null Safety](#lesson-9) [10. Async and Await](#lesson-10) [11. Practice Task](#lesson-11) [12. Next Step](#lesson-12) [Quiz](#lesson-quiz) [Glossary](#lesson-glossary)
Before You Start: How Programming Works
A program is just a list of instructions. Dart reads your instructions and runs them step by step.
- Compilation: Dart checks and prepares your code.
- Runtime: your program is actually executing.
- Data: values your program uses and changes.
- Control flow: decisions and repetition.
Who Should Learn Dart?
Dart is great for:
- Beginners who want a clean modern language.
- Flutter developers building mobile/web/desktop apps.
- Backend developers using Dart services and APIs.
- Teams that prefer one language across app + server.
1. First Program
Your app needs one known starting point. In Dart, that starting point is main(). Without it, Dart does not know where execution begins.
Use code below only as a minimal illustration.
Understand The Line
print: built-in function that writes text to console.
( ): function input area (argument list).
'Hello, Dart!': a string (text value).
;: statement ends here.
Understand The Entry Point
void: this function returns no value.
main: special name Dart looks for first.
(): parameter list (empty in this example).
{ }: the function body (code that runs).
Beginner checks:
- If you rename
maintomains, Dart will not find the normal entry point.
- If you remove
(), function syntax is invalid.
- If you remove
{}, block-style function will not work.
2. Variables and Types
A variable is a named box that stores data.
Before code, understand the 4 basic data types:
String: text like names, emails, titles.
int: whole numbers like age, count, quantity.
double: decimal numbers like price, score, rating.
bool: onlytrueorfalse.
Why variables are important: if one value appears in 10 to 50 places, changing every place manually is hard and risky. With one variable, you change it once and all usage updates automatically.
Real-Life Illustration
Imagine a tax rate used in many screens and calculations. Hardcoding 0.15 everywhere means big effort later. Store it once in a variable, then reuse it everywhere.
Basic type illustration:
Can Variables Be Updated?
Why Types Help Beginners
- You catch mistakes earlier.
- Your editor can suggest better autocomplete.
- Code becomes easier to explain and review.
Try Wrong Type (See The Error)
If a variable is int, you cannot assign text to it. Dart will stop you at compile time.
You will see an error like:
3. Working With Data Types
After you know types, the next step is using their built-in methods. Methods are helper actions you can call on values.
String Methods (Text)
Number Methods (int / double)
Boolean: Only true or false
A boolean value can only be true or false.
Use booleans for yes/no decisions: access granted, loading done, email verified, etc.
4. Operators (Before If Statement)
Operators are symbols Dart uses to compare, calculate, or combine values. You need them before condition flow because if checks expressions built with operators.
Arithmetic Operators
Dart can perform arithmetic and follows normal math order rules: BODMAS / PEDMAS (parentheses first, then multiply/divide, then add/subtract).
Comparison Operators
5. If, Else, and Loops
What is an if statement? It is how your program makes decisions. If a condition is true, run one block. Otherwise run another block.
Why use it? Real apps are not one fixed path. User role, score, payment status, and login state all change behavior.
When to use it? Anytime your logic has choices.
Comparison Operators (Conditions)
else if (Many choices)
Nested if (if inside if)
Use nested if only when logic is truly inside another condition. If it gets deep, move logic into functions.
Using && and ||
switch case
Use switch when one value can match many known options. It keeps code cleaner than long else if chains.
Loops (When To Use Each Type)
Use loops when you need repetition. The best loop depends on your goal.
1) for loop
Use for when you know how many times to repeat. Great for counters, index-based loops, fixed rounds.
int square(int x) => x * x; String greet(String name) => 'Hello $name';
// Good arrow usage (simple one expression) bool isAdult(int age) => age >= 18;
// Better as block (multiple decisions) String grade(int score) { if (score >= 90) return 'A'; if (score >= 80) return 'B'; return 'C'; }
void welcome(String name) { // name = parameter print('Welcome $name'); }
void main() { welcome('Ada'); // 'Ada' = argument }
void createUser({required String name, int age = 18}) { print('name=$name age=$age'); }
void main() { createUser(name: 'Ada'); createUser(name: 'Linus', age: 25); }
void logMessage(String message, [String level = 'INFO']) { print('[$level] $message'); }
void main() { logMessage('App started'); // uses default level logMessage('Disk almost full', 'WARN'); }
int add(int a, int b) { return a + b; }
void main() { final total = add(4, 6); print(total); // 10 }
void main() { final nums = [3, 1, 2];
nums.add(4); // 1) add nums.addAll([5, 6]); // 2) addAll nums.insert(0, 99); // 3) insert nums.remove(1); // 4) remove(value) nums.removeAt(0); // 5) removeAt(index) print(nums.contains(3)); // 6) contains print(nums.indexOf(4)); // 7) indexOf nums.sort(); // 8) sort final filtered = nums.where((n) => n > 3).toList(); // 9) where final doubled = nums.map((n) => n * 2).toList(); // 10) map print(nums.first); // 11) first print(nums.last); // 12) last print(nums.length); // 13) length
// Optional: // nums.clear(); // clear all items
print(nums); print(filtered); print(doubled); }
void main() { final user = {'name': 'Ada', 'role': 'dev'};
user['age'] = 22; // 1) set by key user.putIfAbsent('city', () => 'Lagos'); // 2) putIfAbsent user.update('role', (v) => 'admin'); // 3) update user.addAll({'active': true}); // 4) addAll print(user.containsKey('name')); // 5) containsKey print(user.containsValue('admin')); // 6) containsValue print(user.keys); // 7) keys print(user.values); // 8) values print(user.entries); // 9) entries user.forEach((k, v) => print('$k => $v')); // 10) forEach final upperKeys = user.map((k, v) => // 11) map MapEntry(k.toUpperCase(), v)); user.remove('city'); // 12) remove print(user.length); // 13) length
// Optional: // user.clear(); // clear all pairs
print(upperKeys); }
class User { final String name; final int age;
User(this.name, this.age);
String intro() => 'I am $name and I am $age.'; }
void main() { final user = User('Ada', 22); print(user.intro()); }
void main() { String? nickname; print(nickname ?? 'No nickname');
String name = 'Ada'; print(name.length); }
Future fetchUser() async { await Future.delayed(const Duration(seconds: 1)); return 'Ada'; }
Future main() async { final user = await fetchUser(); print(user); }
Build routes, controllers, APIs, docs, and browser UI from one Dart-shaped stack.