DART: Variables and Data Types

Variables are the foundation of any Dart program. Dart is a statically typed language, but offers both explicit type annotations and type inference. Understanding the full range of data types — from primitives to collections — and how to convert between them is essential for writing correct Dart code.

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

KeywordDescription
varType is inferred from the assigned value
String, int, etc.Explicit static type annotation
dynamicCan hold any type at runtime
finalValue can only be set once (runtime constant)
constCompile-time constant — value is fixed at compile time

dart
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:

dart
int count = 100;
var steps = 10000;

double temperature = 36.7;
var price = 9.99;

TypeDescriptionExample
intInteger values, no decimal42, -7, 0
doubleFloating-point values3.14, -0.5

Both int and double are subtypes of num.

Booleans

dart
bool isLoggedIn = true;
var hasError = false;

Strings

Strings can use single quotes, double quotes, raw strings, or multi-line strings:

dart
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 $:

dart
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:

dart
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.

dart
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.

dart
// 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.

dart
// 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:

dart
// 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.

dart
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.

dart
// 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:

dart
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

dart
// 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

dart
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

md
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.