Skip to main content

Advanced Features


Callable Classes

// A class with call() method can be invoked like a function
class Multiplier {
final int factor;
Multiplier(this.factor);

int call(int value) => value * factor;
}

var triple = Multiplier(3);
print(triple(5)); // 15 — calls triple.call(5)
print(triple(10)); // 30

// Useful for dependency injection
class Logger {
void call(String message) => print('[LOG] $message');
}
var log = Logger();
log('Hello!'); // [LOG] Hello!

Metadata / Annotations

// Built-in annotations
// override a parent method
// mark as deprecated
('Use newMethod() instead')
('vm:entry-point') // prevent tree shaking

// Custom annotations
class Required {
const Required();
}

class Range {
final int min, max;
const Range(this.min, this.max);
}

class UserModel {
()
String name;

(0, 150)
int age;

UserModel(this.name, this.age);
}

// Annotations are primarily used by code generators (build_runner)
()
class User {
final String name;
final int age;
User(this.name, this.age);
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}

Operator Overloading (in depth)

class Money {
final int cents;
final String currency;

const Money(this.cents, [this.currency = 'USD']);

Money operator +(Money other) {
assert(currency == other.currency, 'Currency mismatch');
return Money(cents + other.cents, currency);
}

Money operator -(Money other) => Money(cents - other.cents, currency);
Money operator *(double factor) => Money((cents * factor).round(), currency);

bool operator <(Money other) => cents < other.cents;
bool operator >(Money other) => cents > other.cents;


bool operator ==(Object other) =>
other is Money && cents == other.cents && currency == other.currency;


int get hashCode => Object.hash(cents, currency);


String toString() {
var dollars = cents ~/ 100;
var centPart = (cents % 100).toString().padLeft(2, '0');
return '\$$dollars.$centPart $currency';
}
}

var price = Money(999); // $9.99
var tax = Money(80); // $0.80
var total = price + tax; // $10.79
print(total); // $10.79 USD
print(total > Money(1000)); // false

Isolates (Deep Dive)

import 'dart:isolate';

// Simple: Isolate.run for one-off computation
Future<int> heavyWork() async {
return await Isolate.run(() {
// Runs in separate isolate (thread)
var result = 0;
for (var i = 0; i < 1000000000; i++) result += i;
return result;
});
}

// Complex: Isolate with SendPort/ReceivePort for two-way communication
void isolateMain(SendPort sendPort) {
var receivePort = ReceivePort();
sendPort.send(receivePort.sendPort); // send our port back

receivePort.listen((message) {
// Process message and send result
var result = processData(message);
sendPort.send(result);
});
}

Future<void> main() async {
var receivePort = ReceivePort();
var isolate = await Isolate.spawn(isolateMain, receivePort.sendPort);

var isolateSendPort = await receivePort.first as SendPort;

// Send work to isolate
var responsePort = ReceivePort();
isolateSendPort.send({'work': 'data', 'replyTo': responsePort.sendPort});
var result = await responsePort.first;

isolate.kill();
}

Zones

import 'dart:async';

// Zones allow you to intercept async operations
void main() {
runZonedGuarded(
() async {
// Code running in this zone
throw Exception('Unhandled error');
},
(error, stack) {
// Catch all unhandled errors in this zone
print('Caught: $error');
print('Stack: $stack');
},
);
}

Late Final Initialization Pattern

class ServiceLocator {
static final ServiceLocator _instance = ServiceLocator._();
factory ServiceLocator() => _instance;
ServiceLocator._();

late final Database _database;
late final ApiClient _apiClient;
bool _initialized = false;

Future<void> initialize() async {
assert(!_initialized, 'Already initialized');
_database = await Database.open('app.db');
_apiClient = ApiClient(baseUrl: 'https://api.example.com');
_initialized = true;
}

Database get database {
assert(_initialized, 'Call initialize() first');
return _database;
}
}