Skip to content
AgileLogics
5 min read

Records

Prerequisites: Functions, Maps

A record (Dart 3+) bundles a few values together without defining a class. Records are immutable, can mix types, and are compared by their values.

Positional and named fields

void main() {
  final point = (3, 4);
  print(point);
  print(point.$1);
  print(point.$2);

  final user = (name: 'Ada', age: 36);
  print(user);
  print(user.name);

  final mixed = ('Ada', age: 36);
  print(mixed.$1);
  print(mixed.age);

  print((1, 2) == (1, 2));
}
(3, 4)
3
4
(age: 36, name: Ada)
Ada
Ada
36
true
  • Positional fields are read with $1, $2, ...
  • Named fields are read by name. Their order doesn't matter — (name: 'Ada', age: 36) and (age: 36, name: 'Ada') are the same record — which is why printing lists them alphabetically.
  • Two records with the same values are equal.

Returning several values

Records shine as return values:

(int, int) minMax(List<int> numbers) {
  var low = numbers.first;
  var high = numbers.first;
  for (final n in numbers) {
    if (n < low) low = n;
    if (n > high) high = n;
  }
  return (low, high);
}

void main() {
  final (low, high) = minMax([4, 9, 1]);
  print('$low to $high');
}
1 to 9

final (low, high) = ... destructures the record into two variables — the next lesson covers patterns like this in depth.

Record types

The type of (name: 'Ada', age: 36) is ({String name, int age}). Give a long record type a name with a typedef:

typedef Coordinates = ({double lat, double lng});

Coordinates london() => (lat: 51.5, lng: -0.12);

void main() {
  final c = london();
  print('${c.lat}, ${c.lng}');
}
51.5, -0.12

Records or classes?

Records suit small, local groupings — two or three values returned from a function. For data passed widely around your app, with methods or validation, define a class.