Every value in a Dart program is stored in a variable. Understanding how Dart represents data — the types available, how they behave, and how to convert between them — is the necessary foundation before writing any meaningful logic.
What Are Variables?
A variable is a named container that holds a value. In Dart, all variables are initialized to null by default unless explicitly assigned a value (assuming nullable types are in use).
Dart supports both static and dynamic type definitions, giving you flexibility depending on the situation.
Variable Declaration Keywords
| Keyword | Description |
|---|---|
var | Type is inferred from the assigned value |
String, int, etc. | Explicit static type annotation |
dynamic | Can hold any type at runtime |
final | Value can only be set once (runtime constant) |
const | Compile-time constant — value is fixed at compile time |
var name = 'Amr'; // Inferred as String
String city = 'Cairo'; // Explicit type
dynamic anything = 42; // Can change type at runtime
final score = 95; // Set once, cannot be reassigned
const pi = 3.14159; // Compile-time constant
Primitive Data Types
Numbers
Dart has two numeric types:
int count = 100;
var steps = 10000;
double temperature = 36.7;
var price = 9.99;
| Type | Description | Example |
|---|---|---|
int | Integer values, no decimal | 42, -7, 0 |
double | Floating-point values | 3.14, -0.5 |
Both int and double are subtypes of num.
Booleans
bool isLoggedIn = true;
var hasError = false;
Strings
Strings can use single quotes, double quotes, raw strings, or multi-line strings:
var s1 = 'single quotes';
var s2 = "double quotes";
var s3 = r'raw string: \n is NOT a newline here';
var s4 = '''
multi-line
string
''';
var s5 = """another multi-line
string""";
String interpolation embeds expressions directly in a string using $:
String name = 'Amr';
int age = 30;
print('Name: $name, Age: $age');
print('Next year: ${age + 1}');
Null
In Dart's sound null safety system, variables are non-nullable by default. To allow null, append ? to the type:
String name = 'Amr'; // Cannot be null
String? nickname; // Can be null (defaults to null)
Dynamic Variables
The dynamic type allows a variable to hold values of any type. The type check is deferred to runtime. Use sparingly — it bypasses static analysis.
dynamic variable = 100;
print('As number: $variable');
variable = 'Dart Programming';
print('As string: $variable');
variable = true;
print('As bool: $variable');
Final vs Const
Both final and const create variables that cannot be reassigned, but they differ in when the value is determined.
// final — value determined at runtime, set once
final DateTime now = DateTime.now(); // Computed at runtime
final List<String> names = ['Alice', 'Bob']; // Can mutate the list content
// const — value determined at compile time
const double pi = 3.14159;
const String appName = 'MyApp';
const List<int> primes = [2, 3, 5, 7]; // The list itself is immutable
Collection Types
Dart has three built-in collection types: List, Set, and Map.
List (Ordered, Allows Duplicates)
A List is an ordered sequence of values — equivalent to an array in other languages.
// Dynamic (mixed types)
List data = ['Amr', 'Tarek', 30];
print(data[0]); // Amr
print(data.length); // 3
// Typed (only strings)
List<String> names = ['Alice', 'Bob', 'Charlie'];
names[1] = 'David';
print(names[1]); // David
// Immutable list
List<String> frozen = const ['Red', 'Green', 'Blue'];
// frozen[0] = 'Yellow'; // ERROR: Cannot modify an unmodifiable list
// Copy by value (spread operator)
List<String> original = ['a', 'b', 'c'];
List<String> copy = [...original];
copy[0] = 'x';
print(original[0]); // a (unchanged)
print(copy[0]); // x
Copy by reference vs. copy by value:
// By reference (default)
List<String> a = ['one', 'two'];
var b = a; // b points to the same list
a[0] = 'modified';
print(b[0]); // modified (b reflects the change)
// By value (spread operator)
var c = [...a]; // c is an independent copy
a[0] = 'again';
print(c[0]); // modified (c is not affected)
Set (Unordered, Unique Values)
A Set automatically eliminates duplicates.
var halogens = {'fluorine', 'chlorine', 'bromine', 'fluorine'};
print(halogens.length); // 3 (duplicate 'fluorine' removed)
// Typed empty set
Set<String> tags = {};
tags.add('flutter');
tags.add('dart');
tags.add('flutter'); // Duplicate ignored
print(tags.length); // 2
Map (Key-Value Pairs)
A Map stores unordered key-value pairs — similar to a dictionary or hash map.
// Literal syntax
Map<String, int> scores = {
'Alice': 90,
'Bob': 85,
'Charlie': 95,
};
print(scores['Alice']); // 90
// Constructor syntax
var gifts = Map<String, String>();
gifts['first'] = 'Mango';
gifts['second'] = 'T-shirt';
// Access with null-safe default
int bobScore = scores['Bob'] ?? 0;
Common Collection Methods
All Dart collections are objects with rich method sets:
List<int> numbers = [3, 1, 4, 1, 5, 9, 2, 6];
numbers.add(7); // Add to end
numbers.remove(1); // Remove first occurrence of 1
numbers.sort(); // Sort in place
print(numbers.contains(5)); // true
print(numbers.length); // Length
print(numbers.first); // First element
print(numbers.last); // Last element
print(numbers.isEmpty); // false
print(numbers.reversed.toList()); // Reversed copy
Type Conversion
Number and String Conversions
// String --> int
var one = int.parse('1');
assert(one == 1);
// String --> double
var pi = double.parse('3.14');
assert(pi == 3.14);
// int --> String
String oneStr = 1.toString();
assert(oneStr == '1');
// double --> String (with fixed decimal places)
String piStr = 3.14159.toStringAsFixed(2);
assert(piStr == '3.14');
Checking Types
dynamic value = 42;
if (value is int) {
print('It is an integer');
}
if (value is! String) {
print('It is not a string');
}
// Safe cast
String? text = value as String?; // Returns null if cast fails (with ?)
Variables at a Glance
Dart Variable Keywords
-----------------------
var --> Inferred type, can be reassigned
String --> Explicit type, can be reassigned
dynamic --> Any type, runtime type checking
final --> Set once (runtime value)
const --> Set at compile time, deeply immutable
Nullable vs Non-nullable
------------------------
String name --> cannot be null (null safety default)
String? alias --> can be null (opt-in nullable)
Mastering these fundamentals means you can accurately model any data your application needs and avoid the class of runtime errors that come from unexpected null values or wrong type assumptions.