Dart Programming: Complete Beginner's Guide
Dart is a client-optimized programming language developed by Google. It’s designed for building fast apps on any platform — mobile, desktop, web, and server. Dart is the language behind Flutter, the most popular cross-platform mobile framework.
In this tutorial, you’ll learn Dart syntax, null safety, object-oriented programming, collections, async programming with Future and Stream, and how Dart powers the Flutter framework.
What You’ll Learn
- Dart syntax: variables, functions, control flow
- Null safety with nullable and non-nullable types
- OOP: classes, constructors, inheritance, mixins
- Collections: List, Set, Map, and their methods
- Async: Future, async/await, Stream
- Flutter framework introduction
Why Dart Matters
Dart powers Flutter, which is used by Google, BMW, eBay, and Alibaba for cross-platform mobile apps. It compiles to native ARM code for mobile, JavaScript for web, and x64 for desktop. At DodaTech, we use Flutter/Dart for Doda Browser’s mobile companion app.
Learning Path
flowchart LR
A[OOP Basics] --> B[Dart Basics<br/>You are here]
B --> C[Null Safety]
C --> D[Async Programming]
D --> E[Flutter Apps]
style B fill:#f90,color:#fff
Dart Syntax
Dart syntax is familiar if you know Java, C#, or JavaScript:
void main() {
// Type inference with var
var name = 'Dart';
final version = 3.4; // Single assignment
const pi = 3.14159; // Compile-time constant
// String interpolation
print('Hello, $name! Version $version');
// Hello, Dart! Version 3.4
// Functions
int add(int a, int b) => a + b;
print(add(5, 3)); // 8
}Expected output: Hello, Dart! Version 3.4 and 8.
Null Safety
Dart’s type system distinguishes nullable from non-nullable types:
void main() {
// Non-nullable — cannot be null
String name = 'Alice';
// name = null; // Compile error
// Nullable — can be null
String? nullable = 'Bob';
nullable = null; // OK
// Null-aware operators
int? length = nullable?.length; // null if nullable is null
print(length); // null
// Null coalescing (??)
int len = nullable?.length ?? 0;
print(len); // 0
// Null assertion (use carefully!)
// int sure = nullable!.length; // Throws if nullable is null
// Late initialization
late String databaseUrl; // Initialized lazily
databaseUrl = 'https://api.example.com';
}Expected output: null then 0. Dart’s null safety catches null errors at compile time, preventing null pointer exceptions.
Object-Oriented Programming
Dart is fully object-oriented with classes, constructors, and mixins:
class Animal {
String name;
int age;
// Constructor with syntactic sugar
Animal(this.name, this.age);
// Named constructor
Animal.newborn(this.name) : age = 0;
// Method
void speak() => print('...');
}
class Dog extends Animal {
Dog(String name, int age) : super(name, age);
@override
void speak() => print('$name says Woof!');
// Named parameters
void fetch({required String item, int times = 1}) {
for (var i = 0; i < times; i++) {
print('Fetching $item ($i)');
}
}
}
void main() {
var dog = Dog('Rex', 3);
dog.speak(); // Rex says Woof!
dog.fetch(item: 'ball'); // Fetching ball (0)
}Expected output: Rex says Woof! then Fetching ball (0).
Collections
Dart provides List, Set, and Map with powerful methods:
void main() {
// List
var numbers = [3, 1, 4, 1, 5];
numbers.sort();
print(numbers); // [1, 1, 3, 4, 5]
// Map with spread
var scores = {'Alice': 95, 'Bob': 87};
var updated = {...scores, 'Charlie': 92};
print(updated); // {Alice: 95, Bob: 87, Charlie: 92}
// Collection operations
var evens = numbers.where((n) => n.isEven).toList();
print(evens); // [4]
var doubled = numbers.map((n) => n * 2).toList();
print(doubled); // [2, 2, 6, 8, 10]
}Expected output: [1, 1, 3, 4, 5], {Alice: 95, Bob: 87, Charlie: 92}, [4], [2, 2, 6, 8, 10].
Async Programming
Dart uses Future for single async values and Stream for sequences:
// Simulate network request
Future<String> fetchUserData(int id) async {
await Future.delayed(Duration(seconds: 1));
return 'User $id data';
}
Future<void> main() async {
print('Fetching...');
// Sequential
var user1 = await fetchUserData(1);
print(user1); // User 1 data
// Concurrent
var results = await Future.wait([
fetchUserData(2),
fetchUserData(3),
]);
print(results); // [User 2 data, User 3 data]
// Stream
var stream = Stream.periodic(
Duration(seconds: 1), (i) => 'Tick $i').take(3);
await for (var msg in stream) {
print(msg);
}
// Tick 0 (after 1s)
// Tick 1 (after 2s)
// Tick 2 (after 3s)
}Expected behavior: Fetches user 1 sequentially (1s), then users 2 and 3 concurrently (1s total), then prints three ticks at 1s intervals.
Flutter Framework
Flutter uses Dart to build native-compiled mobile, web, and desktop apps from a single codebase:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Hello Flutter',
home: Scaffold(
appBar: AppBar(title: const Text('Hello')),
body: const Center(
child: Text('Hello, Flutter!'),
),
),
);
}
}Expected behavior: Renders a full-screen mobile app with an app bar and centered text, compiling to native ARM code.
Common Mistakes
1. Using var When Initialization Type Is Unclear
var is fine for obvious types. For complex expressions, use explicit types for readability.
2. Forgetting Null Safety
String? is nullable; String is not. The compiler enforces this. Add ? for any variable that might be null.
3. Blocking the UI Thread
Dart runs on a single thread. Long synchronous operations freeze the UI. Always use async/Future for I/O.
4. Not Using const for Widgets
In Flutter, const constructors reduce rebuild overhead. Use const Text(...) wherever possible.
5. Confusing == and === (identical)
== checks structural equality. identical(a, b) checks reference equality.
6. Ignoring the Linter
Run dart analyze to catch common issues. Follow the Dart style guide for consistent code.
Practice Questions
1. What does ? after a type mean?
The type is nullable. Without ?, the type cannot hold null — enforced at compile time.
2. What is a Future?
A Future represents a single asynchronous value that will be available later. Use async/await to work with it.
3. How is inheritance implemented in Dart?
With class Dog extends Animal. Constructors use super() to pass parameters to the parent class.
4. What’s the difference between var, final, and const?
var type-inferred, reassignable. final single-assignment at runtime. const compile-time constant.
5. Challenge: Build a simple async counter.
Create a Stream that emits ascending integers every 500ms. Listen for 10 values, then cancel.
Mini Project: File Word Counter
import 'dart:io';
Future<void> main(List<String> args) async {
var file = File(args[0]);
var contents = await file.readAsString();
var words = contents.split(RegExp(r'\s+'));
print('Word count: ${words.length}');
}FAQ
What’s Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro