Dart Introduction

Dart is Google's client-optimized programming language, most famous as the language behind Flutter. It's fast, productive, and type-safe.

Why Dart?

  • Flutter's language — #1 choice for cross-platform mobile dev
  • AOT + JIT — Fast development (hot reload) + fast production (compiled)
  • Null safety — Eliminates null reference errors at compile time
  • Familiar syntax — Easy to learn if you know Java, JavaScript, or C#
  • Rich libraries — Async, collections, math, JSON — all built-in
  • Cross-platform — iOS, Android, web, desktop, server

Hello World

Dart
void main() {
  print("Hello, World!");
  
  // Variables
  var name = "Alice";        // Inferred type
  String city = "New York";  // Explicit type
  int age = 28;              // Explicit type
  
  // String interpolation
  print('Hello, $name!');
  print('${name.toUpperCase()} is $age years old');
}

Null Safety — Dart's Superpower

Dart
// Nullable types (can be null)
String? nullable = null;   // OK
String definite = "hello"; // Cannot be null

// Safe access operators
String? name = null;
print(name?.length);       // null (no crash!)
print(name ?? "default");  // "default" (fallback value)
print(name!.length);       // ERROR! (force unwrap — dangerous)

// If null check
if (name != null) {
  print(name.length);  // Smart cast — name is String here
}

// Late variables (initialized later)
late String expensive;
if (condition) {
  expensive = computeExpensiveValue();
}

// Cascade notation (chain operations on same object)
var button = Button()
  ..text = "Click me"
  ..color = Colors.blue
  ..onPressed = () => print("Clicked!");

Functions

Dart
// Arrow functions (one-liners)
int add(int a, int b) => a + b;
String greet(String name) => "Hello, $name!";

// Named parameters (must be called by name)
void createUser({required String name, int age = 0, String? email}) {
  print("$name is $age years old");
}

createUser(name: "Alice");                           // OK
createUser(name: "Bob", age: 35, email: "b@m.com"); // OK

// Optional positional parameters
String formatName(String first, [String? last]) {
  return last != null ? "$first $last" : first;
}

formatName("Alice");           // "Alice"
formatName("Alice", "Smith");  // "Alice Smith"

// First-class functions
var multiply = (int a, int b) => a * b;
print(multiply(3, 4));  // 12

// Higher-order functions
void applyTwice(int value, Function(int) f) {
  print(f(f(value)));
}

applyTwice(3, (x) => x * 2);  // 12 (3*2=6, 6*2=12)

Collections

Dart
// Lists (ordered, mutable)
var fruits = ["apple", "banana", "cherry"];
fruits.add("date");
fruits.addAll(["elderberry", "fig"]);
fruits.removeAt(0);

// List operations
fruits.map((f) => f.toUpperCase()).toList();
fruits.where((f) => f.startsWith("b")).toList();
fruits.any((f) => f.length > 5);        // true/false
fruits.every((f) => f.length > 2);       // true/false
fruits.fold(0, (sum, f) => sum + f.length); // 20

// Spread operator
var all = [...fruits, "grape"];

// Conditional element
var list = [
  "item1",
  if (includeItem2) "item2",
  for (var i = 0; i < 3; i++) "repeated_$i",
];

// Maps (key-value)
var scores = {"Alice": 95, "Bob": 87};
scores["Alice"] = 95;
scores.containsKey("Alice");  // true
scores.remove("Bob");

// Sets (unique elements)
var colors = {"red", "green", "blue"};
colors.add("red");  // Already exists, no change
colors.union({"yellow"});  // {"red","green","blue","yellow"}

Classes

Dart
class User {
  final String name;
  final String email;
  int _age;  // Private (underscore prefix)
  
  // Constructor
  User({required this.name, required this.email, int age = 0})
    : _age = age;
  
  // Named constructors
  User.anonymous() : name = "Anonymous", email = "";
  User.fromJson(Map<String, dynamic> json)
    : name = json['name'],
      email = json['email'];
  
  // Getter
  bool get isAdult => _age >= 18;
  
  // Setter
  set age(int value) {
    if (value < 0) throw ArgumentError("Age cannot be negative");
    _age = value;
  }
  
  @override
  String toString() => 'User($name, $email)';
}

// Inheritance
class Admin extends User {
  List<String> permissions;
  
  Admin({required String name, required String email, this.permissions = []})
    : super(name: name, email: email);
  
  bool hasPermission(String perm) => permissions.contains(perm);
}

Knowledge Check

4 questions — test your understanding

1

What does `String?` mean in Dart?

2

What is the purpose of the `late` keyword?

3

What does `..` (cascade) do in Dart?

4

What does `required` mean before a named parameter?