January 15, 2025 · 4 min read
Dart Basics: From Entry Point to Collections
A whirlwind tour of Dart's fundamentals — the entry point, variables, data types, control flow, and the core collections (List, Set, Map) you'll use in every program.
If you're coming to Dart from another language, most of it will feel familiar — but the details are worth getting right from day one. This is a whirlwind tour of the fundamentals: the entry point, variables, types, control flow, and the core collections you'll use in every program.
The entry point
Every Dart program starts at a top-level main function.
void main() {
print('Hello, Dart');
}
// It can also take command-line arguments:
void main(List<String> args) {
print('You passed ${args.length} args');
}
Variables
Use var to let Dart infer the type, or write the type explicitly. Use final for a value set once, and const for a compile-time constant.
var count = 3; // inferred as int
int total = 10; // explicit
final name = 'Ada'; // set once, at runtime
const pi = 3.14159; // compile-time constant
late String greeting; // initialized later, but before first use
greeting = 'Hi';
Rule of thumb: reach for final by default and only use var when the value genuinely changes.
Data types
The core built-in types:
int age = 30;
double price = 9.99;
num anything = 5; // int or double
String title = 'Dart';
bool isReady = true;
List<int> scores = [1, 2, 3];
Map<String, int> ages = {'Ada': 36};
Object o = 'anything'; // the root type
dynamic d = 'no checks';// opts out of static checking — avoid
Strings support interpolation with $ and ${...}:
final user = 'Sam';
print('Welcome, $user — you have ${scores.length} scores');
Control flow
if / else if / else work as you'd expect, and there's a ternary for short cases.
if (age >= 18) {
print('adult');
} else {
print('minor');
}
final label = age >= 18 ? 'adult' : 'minor';
switch handles multi-way branches, and in modern Dart it can be an expression:
final tier = switch (score) {
>= 90 => 'A',
>= 80 => 'B',
_ => 'C',
};
Lists
An ordered, growable collection.
final fruits = <String>['apple', 'banana'];
fruits.add('cherry');
print(fruits[0]); // apple
print(fruits.length); // 3
print(fruits.contains('banana')); // true
// Transform without a loop:
final upper = fruits.map((f) => f.toUpperCase()).toList();
final short = fruits.where((f) => f.length <= 5).toList();
Loops
Classic for, for-in, and while:
for (var i = 0; i < 3; i++) {
print(i); // 0 1 2
}
for (final fruit in fruits) {
print(fruit);
}
var n = 3;
while (n > 0) {
n--;
}
Dart also has collection-for and collection-if for building lists inline:
final widgets = [
const Header(),
for (final f in fruits) Chip(label: f),
if (isReady) const Footer(),
];
Sets
An unordered collection of unique values.
final tags = <String>{'dart', 'flutter'};
tags.add('dart'); // ignored — already present
print(tags.length); // 2
print(tags.contains('flutter')); // true
final a = {1, 2, 3};
final b = {3, 4};
print(a.intersection(b)); // {3}
print(a.union(b)); // {1, 2, 3, 4}
Maps
Key–value pairs.
final capitals = <String, String>{
'Iraq': 'Baghdad',
'Japan': 'Tokyo',
};
capitals['Egypt'] = 'Cairo';
print(capitals['Japan']); // Tokyo
print(capitals.containsKey('Iraq')); // true
for (final entry in capitals.entries) {
print('${entry.key} -> ${entry.value}');
}
Functions
Functions are first-class. Use arrow syntax for one-liners, and named or optional parameters for clarity.
int add(int a, int b) => a + b;
String greet(String name, {String greeting = 'Hello'}) => '$greeting, $name';
greet('Ada'); // Hello, Ada
greet('Ada', greeting: 'Hi'); // Hi, Ada
Where to go next
That's the toolkit for everyday Dart. Next, learn how these pieces come together in classes and objects — the foundation of Dart's object-oriented model — and lean into the type system: the more precise your types, the more the compiler helps you.