Introduction
Dart is a client-optimized programming language developed by Google, primarily used for building mobile, desktop, server, and web applications. It’s the foundation of Flutter framework and known for its strong typing system, null safety, and modern syntax. Understanding Dart’s basic syntax and type system is crucial for effective Flutter development and general Dart programming.
Why Dart Matters:
- Powers Flutter for cross-platform development
- Compiles to native ARM & x64 machine code
- Features null safety and sound type system
- Supports both AOT and JIT compilation
- Easy to learn for developers coming from Java, C#, or JavaScript
Core Concepts & Principles
1. Everything is an Object
- All values in Dart are objects, including numbers, functions, and null
- Every object is an instance of a class that derives from Object
2. Static Type System with Type Inference
- Dart uses static typing but can infer types automatically
- Variables can be explicitly typed or use
var,dynamic, orObject
3. Null Safety
- Dart 2.12+ enforces null safety by default
- Types are non-nullable unless explicitly marked with
?
4. Sound Type System
- Runtime type checks match static type analysis
- Helps prevent runtime errors and improves performance
Basic Syntax Structure
Program Structure
// Import statements
import 'dart:core';
// Main function (entry point)
void main() {
print('Hello, Dart!');
}
// Function definition
String greetUser(String name) {
return 'Hello, $name!';
}
Comments
// Single-line comment
/*
Multi-line comment
Can span multiple lines
*/
/// Documentation comment
/// Used for generating documentation
Semicolons and Blocks
- Statements end with semicolons (
;) - Code blocks use curly braces (
{}) - Indentation is by convention (2 spaces recommended)
Variable Declaration & Assignment
Declaration Methods
| Method | Description | Example | When to Use |
|---|---|---|---|
var | Type inferred from assignment | var name = 'John'; | When type is obvious |
final | Runtime constant (set once) | final time = DateTime.now(); | For values set once at runtime |
const | Compile-time constant | const pi = 3.14159; | For compile-time known values |
late | Late initialization | late String description; | For non-nullable vars initialized later |
| Explicit type | Direct type specification | String name = 'John'; | For clarity or when needed |
Variable Examples
// Type inference
var count = 42; // int
var message = 'Hello'; // String
var items = <String>[]; // List<String>
// Explicit typing
int age = 25;
String username = 'dart_dev';
bool isActive = true;
// Constants
final currentTime = DateTime.now(); // Runtime constant
const maxRetries = 3; // Compile-time constant
// Late initialization
late String configValue;
void initConfig() {
configValue = 'initialized';
}
Data Types
Primitive Types
Numbers
// Integers
int wholeNumber = 42;
int hexValue = 0xFF;
int negative = -10;
// Doubles (floating-point)
double decimal = 3.14159;
double scientific = 1.42e5;
double negative = -2.5;
// num (supertype of int and double)
num flexible = 42; // Can be int or double
flexible = 3.14; // Now it's double
Strings
// String literals
String single = 'Single quotes';
String double = "Double quotes";
String multiline = '''
Multiple
lines
here''';
// String interpolation
String name = 'Alice';
int age = 30;
String message = 'Hello $name, you are $age years old';
String expression = 'Next year: ${age + 1}';
// Raw strings (no interpolation)
String raw = r'Raw string with $variable and \n';
Booleans
bool isTrue = true;
bool isFalse = false;
bool fromExpression = 5 > 3; // true
// Null safety - nullable boolean
bool? maybeTrue = null;
Collection Types
Lists (Arrays)
// List declaration
List<int> numbers = [1, 2, 3, 4, 5];
var fruits = ['apple', 'banana', 'orange'];
List<String> empty = [];
// List operations
numbers.add(6); // Add element
numbers.addAll([7, 8, 9]); // Add multiple
numbers.insert(0, 0); // Insert at index
numbers.remove(5); // Remove value
numbers.removeAt(0); // Remove at index
// List properties
print(numbers.length); // Get length
print(numbers.isEmpty); // Check if empty
print(numbers.first); // First element
print(numbers.last); // Last element
Sets
// Set declaration
Set<String> colors = {'red', 'green', 'blue'};
var uniqueNumbers = <int>{1, 2, 3, 4, 5};
Set<String> empty = {};
// Set operations
colors.add('yellow'); // Add element
colors.addAll(['purple', 'pink']); // Add multiple
colors.remove('red'); // Remove element
bool hasBlue = colors.contains('blue'); // Check membership
Maps (Key-Value Pairs)
// Map declaration
Map<String, int> scores = {'Alice': 95, 'Bob': 87, 'Charlie': 92};
var userInfo = {
'name': 'John',
'age': 30,
'email': 'john@example.com'
};
// Map operations
scores['David'] = 88; // Add/update entry
scores.remove('Bob'); // Remove entry
bool hasAlice = scores.containsKey('Alice'); // Check key
List<String> names = scores.keys.toList(); // Get keys
List<int> values = scores.values.toList(); // Get values
Null Safety
Nullable vs Non-nullable Types
| Type | Declaration | Description |
|---|---|---|
| Non-nullable | String name | Cannot be null, must be initialized |
| Nullable | String? name | Can be null or contain a String value |
| Late | late String name | Non-nullable but initialized later |
Null Safety Operators
// Null-aware operators
String? nullableName = null;
// Null-aware access (?.)
int? length = nullableName?.length;
// Null coalescing (??)
String displayName = nullableName ?? 'Unknown';
// Null assertion (!)
String definitelyNotNull = nullableName!; // Throws if null
// Null-aware assignment (??=)
nullableName ??= 'Default Name'; // Assign only if null
Null Safety Best Practices
// Good: Check before use
String? getUserName() => null;
void printUserName() {
String? name = getUserName();
if (name != null) {
print('User: $name');
}
}
// Good: Use null coalescing
String getDisplayName(String? name) {
return name ?? 'Anonymous';
}
// Good: Late initialization for non-nullable
class User {
late String name;
void initialize(String userName) {
name = userName;
}
}
Operators
Arithmetic Operators
int a = 10, b = 3;
int sum = a + b; // Addition: 13
int diff = a - b; // Subtraction: 7
int product = a * b; // Multiplication: 30
double quotient = a / b; // Division: 3.333...
int intDiv = a ~/ b; // Integer division: 3
int remainder = a % b; // Modulo: 1
// Increment/Decrement
a++; // Post-increment
++a; // Pre-increment
b--; // Post-decrement
--b; // Pre-decrement
Comparison Operators
bool equal = a == b; // Equal to
bool notEqual = a != b; // Not equal to
bool greater = a > b; // Greater than
bool less = a < b; // Less than
bool greaterEq = a >= b; // Greater than or equal
bool lessEq = a <= b; // Less than or equal
Logical Operators
bool x = true, y = false;
bool and = x && y; // Logical AND
bool or = x || y; // Logical OR
bool not = !x; // Logical NOT
Assignment Operators
int value = 10;
value += 5; // value = value + 5
value -= 3; // value = value - 3
value *= 2; // value = value * 2
value ~/= 4; // value = value ~/ 4
value %= 3; // value = value % 3
Control Flow
Conditional Statements
If-Else
int score = 85;
if (score >= 90) {
print('Grade: A');
} else if (score >= 80) {
print('Grade: B');
} else if (score >= 70) {
print('Grade: C');
} else {
print('Grade: F');
}
// Ternary operator
String result = score >= 60 ? 'Pass' : 'Fail';
Switch Statement
String grade = 'B';
switch (grade) {
case 'A':
print('Excellent!');
break;
case 'B':
print('Good job!');
break;
case 'C':
print('Fair');
break;
default:
print('Keep trying!');
}
Loops
For Loop
// Traditional for loop
for (int i = 0; i < 5; i++) {
print('Count: $i');
}
// For-in loop
List<String> names = ['Alice', 'Bob', 'Charlie'];
for (String name in names) {
print('Hello, $name!');
}
// For-each method
names.forEach((name) => print('Hi, $name!'));
While Loop
int count = 0;
while (count < 5) {
print('Count: $count');
count++;
}
// Do-while loop
int number = 0;
do {
print('Number: $number');
number++;
} while (number < 3);
Functions
Function Declaration & Types
| Function Type | Syntax | Example |
|---|---|---|
| Basic | returnType functionName(parameters) { } | int add(int a, int b) => a + b; |
| Arrow | returnType functionName(parameters) => expression; | String greet(String name) => 'Hello $name'; |
| Anonymous | (parameters) { } or (parameters) => expression | var multiply = (int x, int y) => x * y; |
| Optional Positional | functionName([optional]) | void log(String msg, [String level = 'info']) |
| Named Parameters | functionName({required/optional}) | void createUser({required String name, int? age}) |
Function Examples
// Basic function
int calculateArea(int length, int width) {
return length * width;
}
// Arrow function
double calculateCircumference(double radius) => 2 * 3.14159 * radius;
// Optional positional parameters
void greetUser(String name, [String greeting = 'Hello']) {
print('$greeting, $name!');
}
// Named parameters
void createAccount({
required String username,
required String email,
String? phone,
bool isActive = true
}) {
print('Account created: $username');
}
// Higher-order functions
List<int> processNumbers(List<int> numbers, int Function(int) processor) {
return numbers.map(processor).toList();
}
// Usage examples
greetUser('Alice'); // Uses default greeting
greetUser('Bob', 'Hi'); // Custom greeting
createAccount(username: 'john', email: 'john@email.com');
var doubled = processNumbers([1, 2, 3], (x) => x * 2);
Type System Deep Dive
Type Checking & Casting
// Type checking
dynamic value = 'Hello';
if (value is String) {
print('Length: ${value.length}'); // Smart cast
}
// Type casting
var number = value as String; // Throws if not String
// Safe casting
String? safeString = value as String?;
Generic Types
// Generic class
class Box<T> {
T content;
Box(this.content);
T getContent() => content;
}
// Generic function
T getFirstElement<T>(List<T> list) {
return list.first;
}
// Usage
Box<String> stringBox = Box('Hello');
Box<int> intBox = Box(42);
String firstFruit = getFirstElement(['apple', 'banana']);
Type Aliases
// Type alias for complex types
typedef StringProcessor = String Function(String);
typedef UserMap = Map<String, dynamic>;
// Usage
StringProcessor upperCase = (s) => s.toUpperCase();
UserMap user = {'name': 'Alice', 'age': 30};
Common Challenges & Solutions
Challenge 1: Null Safety Migration
Problem: Converting legacy code to null-safe Dart Solution:
// Before (legacy)
String name;
// After (null-safe)
String? name; // If can be null
late String name; // If initialized later
String name = ''; // If has default value
Challenge 2: Type Inference Confusion
Problem: Unclear when to use var vs explicit types Solution:
// Use var when type is obvious
var names = <String>['Alice', 'Bob']; // Clear it's List<String>
// Use explicit types for clarity
Map<String, List<int>> complexData = {}; // Complex type, be explicit
// Use dynamic sparingly
dynamic jsonData = parseJson(response); // When type truly unknown
Challenge 3: Collection Initialization
Problem: Choosing between different collection types Solution:
// Use List for ordered, indexed access
List<String> orderedItems = ['first', 'second', 'third'];
// Use Set for unique values
Set<String> uniqueTags = {'dart', 'flutter', 'mobile'};
// Use Map for key-value relationships
Map<String, int> inventory = {'apples': 10, 'bananas': 15};
Challenge 4: Function Parameter Confusion
Problem: When to use positional vs named parameters Solution:
// Use positional for obvious, few parameters
int add(int a, int b) => a + b;
// Use named for many parameters or unclear meaning
void createUser({
required String name,
required String email,
int age = 0,
bool isActive = true
}) { }
Best Practices & Tips
Code Style & Conventions
- Use
lowerCamelCasefor variables, methods, and parameters - Use
UpperCamelCasefor classes, enums, and typedefs - Use
lowercase_with_underscoresfor libraries and file names - Prefer
finalovervarwhen the value won’t change - Use
constfor compile-time constants
Performance Tips
// Good: Use const constructors when possible
const widget = Text('Hello');
// Good: Use string interpolation instead of concatenation
String message = 'Hello $name, today is $date';
// Good: Use collection literals
var list = <String>[]; // Instead of List<String>()
var map = <String, int>{}; // Instead of Map<String, int>()
// Good: Use cascade notation for multiple operations
var paint = Paint()
..color = Colors.blue
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
Error Handling
// Use try-catch for error handling
try {
int result = int.parse('not a number');
} catch (e) {
print('Error: $e');
} finally {
print('Cleanup code here');
}
// Use specific exception types when possible
try {
// risky operation
} on FormatException catch (e) {
print('Format error: $e');
} on Exception catch (e) {
print('General error: $e');
}
Memory Management
// Good: Close resources properly
class DatabaseConnection {
void close() {
// cleanup code
}
}
// Good: Use weak references for callbacks to avoid memory leaks
void setupCallback(void Function() callback) {
// Store callback reference appropriately
}
Quick Reference Tables
Common String Methods
| Method | Description | Example |
|---|---|---|
length | Get string length | 'hello'.length // 5 |
isEmpty | Check if empty | ''.isEmpty // true |
contains() | Check substring | 'hello'.contains('ell') // true |
startsWith() | Check prefix | 'hello'.startsWith('he') // true |
endsWith() | Check suffix | 'hello'.endsWith('lo') // true |
substring() | Extract substring | 'hello'.substring(1, 4) // 'ell' |
split() | Split into list | 'a,b,c'.split(',') // ['a','b','c'] |
trim() | Remove whitespace | ' hello '.trim() // 'hello' |
toUpperCase() | Convert to uppercase | 'hello'.toUpperCase() // 'HELLO' |
toLowerCase() | Convert to lowercase | 'HELLO'.toLowerCase() // 'hello' |
Common List Methods
| Method | Description | Example |
|---|---|---|
add() | Add single element | list.add('item') |
addAll() | Add multiple elements | list.addAll(['a', 'b']) |
insert() | Insert at index | list.insert(0, 'first') |
remove() | Remove by value | list.remove('item') |
removeAt() | Remove by index | list.removeAt(0) |
indexOf() | Find index of element | list.indexOf('item') |
contains() | Check if contains | list.contains('item') |
sort() | Sort in place | list.sort() |
reversed | Get reversed view | list.reversed.toList() |
map() | Transform elements | list.map((x) => x * 2) |
Resources for Further Learning
Official Documentation
- Dart Language Tour: https://dart.dev/guides/language/language-tour
- Dart API Reference: https://api.dart.dev/
- Effective Dart Guide: https://dart.dev/guides/language/effective-dart
Interactive Learning
- DartPad: https://dartpad.dev/ (Online Dart editor)
- Dart Codelabs: https://dart.dev/codelabs
- Flutter Widget of the Week: https://www.youtube.com/playlist?list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG
Books & Courses
- “Dart in Action” by Chris Buckett
- “Flutter in Action” by Eric Windmill
- Dart/Flutter courses on Udemy, Coursera, and YouTube
Community Resources
- Dart GitHub: https://github.com/dart-lang/dart
- Stack Overflow: Tag questions with
dart - Reddit: r/dartlang and r/FlutterDev
- Discord: Flutter Community Discord Server
Tools & IDEs
- VS Code: With Dart and Flutter extensions
- Android Studio/IntelliJ: With Dart and Flutter plugins
- Vim/Emacs: With appropriate Dart language support
- Online IDEs: CodePen, Repl.it with Dart support
This cheatsheet covers Dart’s fundamental syntax and type system. For advanced topics like asynchronous programming, object-oriented features, and Flutter-specific concepts, refer to the additional resources provided.
