language-dartlisted
Install: claude install-skill lugassawan/swe-workbench
# Dart
## Null safety
- Sound null safety is on by default (Dart ≥2.12) — no unsound nulls sneak through.
- Non-nullable is the default; append `?` only when a value can genuinely be absent (`String? name`).
- `late` defers initialization for values assigned before first read (DI fields, `initState` fields) — a `late` field read before assignment throws.
- `!` (null-assertion) asserts non-null; prefer narrowing (`if (x != null)`) or `?.`/`??` over `!`, since `!` throws at runtime.
- `??=` for lazy default assignment; `??` for fallback expressions.
```dart
String greet(String? name) => 'Hello, ${name ?? 'stranger'}';
```
## Async — Futures and Streams
- `Future<T>` wraps a value that arrives later; `async`/`await` reads like sync code.
- Unhandled Future errors surface as unhandled exceptions — always `try`/`catch` around `await`, or attach `.catchError`.
- `Stream<T>` models a sequence over time; `await for` consumes it, `StreamController` produces it.
- `Completer<T>` bridges callback-based APIs into a `Future`.
- `Future.wait([...])` for concurrent futures; don't `await` sequentially in a loop when the work is independent.
```dart
Future<User> fetchUser(String id) async {
try {
final res = await api.get('/users/$id');
return User.fromJson(res.data);
} on DioException catch (e) {
throw UserFetchException(id, e);
}
}
```
## Widget composition
- `StatelessWidget` is the default; reach for `StatefulWidget` only when the widget owns mutable state across re