iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Dart in 10 mins

Dart is the language Flutter is written in: sound null safety, strong types, JIT for dev / AOT for release, async/await, isolates for parallel work. Modern Java-adjacent syntax with functional flourishes.

Variables, functions, classes, async

EXAMPLE
// 1) Variables + type inference
void main() {
    int    count   = 42;                           // explicit
    var    name    = 'Ada';                         // String — inferred
    final  email   = 'a@x.com';                     // immutable, runtime
    const  pi      = 3.14159;                       // compile-time constant
    String? maybe  = null;                          // nullable (sound null safety)
    late int delayedInit;                            // promised non-null later

    delayedInit = 100;
    print(name);
}

// 2) Strings
var greeting = 'Hello, $name!';
var multi    = '''multi-line
string''';
var raw      = r'Raw \\n is literal';
var runes    = '🇦🇺'.runes.toList();
var parsed   = int.parse('42');
var formatted = '${name.toUpperCase()}-${count.toString().padLeft(5, '0')}';

// 3) Numbers, lists, maps
int    i     = 42;
double d     = 3.14;
List<int> nums = [1, 2, 3, 4, 5];
Map<String, int> scores = {'Ada': 95, 'Bo': 88};
Set<String> tags = {'vip', 'beta'};

// Spread, collection if/for
var moreNums = [...nums, 6, 7];
var conditional = [
    'always',
    if (isLoggedIn) 'profile',
    for (var i = 1; i <= 3; i++) 'item-$i',
];

// 4) Null safety operators
String? name;
name?.toUpperCase();                                // safe call
name ?? 'Anonymous';                                 // default
name ??= 'Default';                                  // assign if null
name!.length;                                        // assert non-null (THROWS if null)

// 5) Functions
int add(int a, int b) => a + b;                      // arrow function

int multiply(int a, int b) {                          // block body
    return a * b;
}

// Optional + named parameters
String greet(String name, {String greeting = 'Hello', bool loud = false}) {
    final s = '$greeting, $name';
    return loud ? s.toUpperCase() : s;
}

greet('Ada');
greet('Bo', greeting: 'Hi', loud: true);

// Required named parameters (recommended for readability)
User createUser({required String email, required String name, String? phone}) {
    return User(email: email, name: name, phone: phone);
}

// 6) Anonymous + closures
var nums2 = [1, 2, 3, 4, 5];
var doubled = nums2.map((n) => n * 2).toList();
var evens   = nums2.where((n) => n.isEven).toList();
var sum     = nums2.reduce((a, b) => a + b);

var makeAdder = (int x) => (int y) => x + y;
var add5 = makeAdder(5);
print(add5(10));                                     // 15

// 7) Classes
class User {
    final String name;
    final String email;
    int age;

    User({required this.name, required this.email, this.age = 0});

    // Named constructor
    User.guest()    : name = 'Guest', email = '',  age = 0;
    User.fromMap(Map<String, dynamic> m) :
        name  = m['name'],
        email = m['email'],
        age   = m['age'] ?? 0;

    // Method
    String greet() => 'Hi, $name';

    // Getter
    bool get isAdult => age >= 18;

    // Setter
    set ageInMonths(int months) => age = (months / 12).floor();

    @@override
    String toString() => 'User(name: $name, email: $email)';
}

// Usage
var u = User(name: 'Ada', email: 'a@x.com', age: 32);
u.greet();
print(u.isAdult);

// 8) Inheritance, interfaces, mixins
abstract class Animal {
    String get name;
    String sound();
    void describe() => print('$name says ${sound()}');
}

class Dog extends Animal {
    @@override final String name;
    Dog(this.name);
    @@override String sound() => 'woof';
}

// Interface — Dart has no interface keyword; any class can be implemented
class Loud implements Animal {
    @@override String get name => 'Loud';
    @@override String sound() => 'WOOF!';
    @@override void describe() => print('Loud one');
}

// Mixin
mixin Swimmer {
    void swim() => print('Swimming…');
}

class Duck extends Animal with Swimmer {
    @@override final String name = 'Donald';
    @@override String sound() => 'quack';
}

final d = Duck();
d.describe();
d.swim();

// 9) Records (Dart 3+) — anonymous tuples
var coords = (lat: -33.86, lng: 151.21);
print(coords.lat);                                   // -33.86

(String, int) parse(String s) {
    final parts = s.split(':');
    return (parts[0], int.parse(parts[1]));
}

var (name, port) = parse('localhost:8080');

// 10) Pattern matching (Dart 3+)
String describe(Object o) => switch (o) {
    int i when i < 0    => 'negative $i',
    int i               => 'positive $i',
    String s            => 'string "$s"',
    [int x, int y]      => 'list of two ints',
    {'name': var n}     => 'map with name $n',
    _                   => 'unknown',
};

// Destructure
final user = {'name': 'Ada', 'age': 32};
if (user case {'name': String name, 'age': int age}) {
    print('$name, $age');
}

// 11) Async + await
Future<String> fetchUserName() async {
    final response = await http.get(Uri.parse('https://api.example.com/me'));
    final data = jsonDecode(response.body);
    return data['name'];
}

void main() async {
    final name = await fetchUserName();
    print(name);
}

// Parallel — Future.wait
final results = await Future.wait([
    fetchUser(1),
    fetchUser(2),
    fetchUser(3),
]);

// Try / catch
try {
    final body = await fetchData();
    process(body);
} on http.ClientException catch (e) {
    print('network: $e');
} catch (e, stack) {
    print('unexpected: $e\n$stack');
} finally {
    cleanup();
}

// 12) Streams — async sequences
Stream<int> count(int n) async* {
    for (var i = 0; i < n; i++) {
        await Future.delayed(Duration(seconds: 1));
        yield i;
    }
}

await for (final n in count(5)) {
    print(n);
}

// 13) Isolates — true parallelism
import 'dart:isolate';

int heavyCompute(int n) {
    int total = 0;
    for (var i = 0; i < n; i++) total += i;
    return total;
}

Future<int> runInIsolate(int n) async {
    return await Isolate.run(() => heavyCompute(n));
}

// 14) Enums — first-class with methods (Dart 2.17+)
enum Status {
    active(label: 'Active', code: 'A'),
    paused(label: 'Paused', code: 'P'),
    archived(label: 'Archived', code: 'X');

    final String label;
    final String code;
    const Status({required this.label, required this.code});

    bool get isAlive => this != archived;
}

print(Status.active.label);                          // 'Active'
print(Status.active.isAlive);                        // true

// 15) Extension methods — add to existing types
extension StringExt on String {
    bool get isValidEmail => RegExp(r'^[^@@]+@@[^@@]+\.[^@@]+$').hasMatch(this);
    String get capitalised => this[0].toUpperCase() + substring(1);
}

print('Ada'.capitalised);                            // 'Ada'
print('a@x.com'.isValidEmail);                       // true

// 16) Sealed classes (Dart 3+) — pattern matching for closed hierarchies
sealed class Result<T> {}
class Success<T> extends Result<T> { final T data; Success(this.data); }
class Failure extends Result<Never> { final String error; Failure(this.error); }
class Loading extends Result<Never> {}

String handle(Result<int> r) => switch (r) {
    Success(:final data) => 'Got $data',
    Failure(:final error) => 'Error: $error',
    Loading()             => 'Loading…',
};

// 17) Common bugs
//   • Forgetting required keyword → null at runtime where compiler couldn't catch
//   • Using ! when value could be null → runtime exception
//   • Mutating final variable → compile error
//   • Mixing types in collections → use explicit types
//   • Not awaiting Future → silent unhandled
//   • Stream subscriptions not cancelled → leaks

// 18) Best practices
//   ✅ Use sound null safety (Dart 2.12+, default in 3.0)
//   ✅ Prefer final over var; const for compile-time constants
//   ✅ Required named parameters for readability
//   ✅ Records + pattern matching for structured data
//   ✅ Sealed classes for discriminated unions
//   ✅ Isolates for CPU-bound parallelism
//   ✅ Extension methods to add behaviour without subclassing
//   ✅ async/await for sequential async; Future.wait for parallel

Why it matters

Modern Dart (3+) gives you records, pattern matching, sealed classes, sound null safety, and isolates — on par with Kotlin and Swift for ergonomics. Use named required parameters, final by default, and pattern matching for type-safe data handling.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
void main() {
    final name = 'Ada';
    print('Hello, $name');
}
Try it Yourself »

Exercise

String interpolation in Dart.

final s = 'Hello, name';

Discussion

Loading…