Irbisa · Cheatsheet

Advanced Dart

Generics, extensions, mixins, isolates, dart:core advanced

Middle Developer · 15 questions

  1. 01

    What is an isolate in Dart, and when should you move work into one?

    An isolate is an independent Dart worker with its own memory and its own event loop, so it runs truly in parallel with the UI isolate.

    import 'dart:convert';import 'dart:isolate'; class User {  final String name;  User(this.name);…
  2. 02

    What does the late modifier actually do, and when is it the wrong tool?

    late lets a non-nullable variable be assigned after its declaration.

    class _EditorState extends State<Editor>    with SingleTickerProviderStateMixin {  // lazy: the initializer needs `this`, so it runs on first read  late final AnimationController _anim = AnimationController(    vsync: this,    duration: const Duration(milliseconds: 200),…
  3. 03

    A crash report says Bad state: No element and points at a firstWhere call. What happened and what do you write instead?

    Nothing matched.

    import 'package:collection/collection.dart'; class Order {  final bool isPending;  final int cents;  const Order(this.isPending, this.cents);…
  4. 04

    How do generics and type bounds work in Dart, and why do reusable widgets and data classes need them?

    A generic class or function takes a type parameter that the caller fills in: Page<T> becomes Page<User>.

    // A bound lets the body call compareTo on TT maxOf<T extends Comparable<T>>(List<T> xs) =>    xs.reduce((a, b) => a.compareTo(b) >= 0 ? a : b); // A generic function: T is fixed per callT first<T>(List<T> xs) => xs.first;…
  5. 05

    Find the bug: markSeen throws at run time instead of remembering that the photo was seen.

    class Photo { Photo(this.id); final int id; }class Meta { bool seen = false; } // Per-photo UI flags without touching Photo.final _meta = Expando<Meta>('photoMeta'); void markSeen(Photo photo) {  final meta = _meta[photo.id] ?? Meta();  meta.seen = true;  _meta[photo.id] = meta;} void main() {  markSeen(Photo(7));  print('marked');}

    Expando attaches data to an object, and the key must be a real object.

  6. 06

    Extension methods: what does this program print, and what single rule explains all four lines?

    class Animal {}class Dog extends Animal {}extension AnimalX on Animal { String speak() => 'animal'; }extension DogX on Dog { String speak() => 'woof'; } class Cat { String speak() => 'meow'; }extension CatX on Cat { String speak() => 'purr'; } void main() {  final Animal a = Dog();  print(a.speak());  print(Dog().speak());  print(Cat().speak());  final dynamic d = Dog();  print(d.speak());}

    It prints animal, woof, meow, then throws NoSuchMethodError.

  7. 07

    Why does list.map(...) run nothing until you call toList(), and when does that laziness bite?

    map, where, expand, take and skip return a lazy Iterable, not a list: your callback runs only when something actually iterates the result.

    void main() {  final nums = [1, 2, 3];   final doubled = nums.map((n) {    print('mapping $n'); // does not run yet    return n * 2;…
  8. 08

    What are sync* and async* generators, and when would you write one?

    A generator produces a sequence one value at a time with yield.

    // sync*: values are produced only as the caller asks for themIterable<int> naturals() sync* {  var n = 0;  while (true) {    yield n++; // naturals().take(3) gives 0, 1, 2  }…
  9. 09

    What does this program with a sync* generator print?

    Iterable<int> count() sync* {  print('start');  for (var i = 1; i <= 3; i++) {    print('yield $i');    yield i;  }  print('end');} void main() {  final numbers = count();  print('created');  print(numbers.first);  print(numbers.first);}

    It prints created, then start, yield 1, 1, and then start, yield 1, 1 again.

  10. 10

    What are Uint8List and the other typed-data lists, and when do you use them instead of List<int>?

    Uint8List, Int32List, Float64List and the rest of dart:typed_data are fixed-length lists stored as one packed block of raw numbers.

    import 'dart:typed_data'; void main() {  final bytes = Uint8List(4);  bytes[0] = 300;  print(bytes[0]); // 44: only the low 8 bits are kept…
  11. 11

    Find the bug: byId[selected.id] prints null although selected comes from the very same list of rows.

    class Row {  Row(this.id, this.text);  final int id;  final String text;} var _nextId = 0;Row _toRow(String line) => Row(_nextId++, line); void main() {  final rows = ['a', 'b', 'c'].map(_toRow);  final selected = rows.first;  final byId = {for (final r in rows) r.id: r};  print(byId[selected.id]?.text);}

    map is lazy: rows is not a list but a recipe that calls _toRow again on every pass.

  12. 12

    What happens between your Dart source and a release binary (kernel, gen_snapshot, tree shaking)?

    The front end compiles Dart to kernel (.dill); in release gen_snapshot turns the whole program into machine code (libapp.so on Android, App.framework on iOS), after whole-program tree shaking removes everything unreachable.

  13. 13

    How does Dart's garbage collector work (young and old generation), and what does it mean for Flutter code?

    Dart uses a generational collector.

  14. 14

    Does Dart have reflection? Why is dart:mirrors unavailable in Flutter, and what do you use instead?

    Dart has reflection in dart:mirrors, but only on the standalone VM.

  15. 15

    How do WeakReference and Expando let the GC reclaim cached objects, and why is a Finalizer not a destructor?

    A normal Map holds strong references, so everything in it stays alive as long as the cache does.

    class DecodedImage { DecodedImage(this.bytes); final int bytes; } // a cache the garbage collector is allowed to emptyclass ThumbCache {  final _entries = <String, WeakReference<DecodedImage>>{};…