Programming with AI
ENRU
11.2

Dart in half an hour

what you need to know in order to read it

What it is

Dart resembles Java, JavaScript and TypeScript at the same time. If you have read chapter 9, half of it is already familiar: types, async/await, classes.

This article covers what differs and what turns up in every file of a Flutter project.

What it looks like in code

class City {
  final String name;
  final double? temp;

  const City({required this.name, this.temp});

  String get report => temp == null
      ? '$name: no data'
      : '$name: ${temp! > 0 ? '+' : ''}$temp°';
}

void main() {
  final cities = <City>[
    const City(name: 'Oslo', temp: 4),
    const City(name: 'Tromsø'),
  ];

  for (final c in cities) {
    print(c.report);
  }
}

What matters here

final instead of const and let. final means assign once. const means the value is known at compile time. In Flutter const turns up constantly: it lets widgets avoid being recreated on a redraw.

double? temp — a type with a question mark, the same as number | null in TypeScript. Dart is as strict about emptiness as TypeScript with strict: you can't reach for temp directly until you have checked.

temp! — the assertion "there is definitely something here". The direct analogue of as from article 9.5 and the same source of trouble: it is a promise to the compiler, not a check. Get it wrong and the application dies with Null check operator used on a null value.

required — a mandatory named parameter. Without it the argument can be left out.

$name and ${expression} — interpolation into a string, like f-strings in Python.

get report => ... — a computed property: accessed like a field, without parentheses.

Named parameters

The main syntactic difference you have to get used to:

City(name: 'Oslo', temp: 4)          // named, in curly braces

In Flutter nearly every parameter is named, and that explains why the code looks so verbose:

Padding(
  padding: const EdgeInsets.all(16),
  child: Text('Hello'),
)

The upside is that while reading you can always see what each value means.

The rest, briefly

Written asWhat it means
late"there will be a value, but later" — a promise, checked at run time
?.safe access, as in JS (article 9.1)
??a default value
..a cascade: several operations on one object
=>the short form of a one-expression function
List<City>a list of cities; <> as in generics (article 9.4)

late is worth a separate mention. It is a way of saying "I will assign this later". If you didn't assign it and then reach for it, you get a run-time error. An AI uses late to get around the initialization requirement — and that is the same gag as as and !.

What to tell the AI

Prompt
Explain this class line by line: what final means, what
required means, what the exclamation mark after temp does.
Prompt
This uses `late` and `!`. Rewrite it without them, with
proper null checks. If there's a place where they can't be
avoided — explain why instead of rewriting it.
Prompt
Write a data model for this API's response: here is a sample
JSON. Make fields that may be absent honestly nullable.
Add a fromJson factory with checks rather than casts.

What to look for

! at every turn. The application will die wherever the data turned out not to be there.

late instead of proper initialization. The same problem, only later.

Code for old Flutter versions. Outdated widget and parameter names.

dynamic. The exact analogue of any from TypeScript: it switches checking off.

JSON parsing with no checks. json['main']['temp'] as double fails if the server answered with an error — exactly as in articles 2.12 and 9.5.

Cheat sheet

  • final means assign once, const means known at compile time.

  • double? may be empty; Dart won't let you reach for it unchecked.

  • !, late and a cast switch off the emptiness check.

  • Parameters in Flutter are nearly always named: City(name: ..., temp: ...).

  • $name and ${expression} interpolate into a string.

  • dynamic is any, with all that follows.