late în Dart

Amână inițializarea unei variabile nenule: valoarea se dă mai târziu sau se calculează la prima folosire.

Sintaxă
late Tip nume;              // primește valoare mai târziu
late final Tip nume;        // o singură dată, mai târziu
late Tip nume = calcul();   // calculat la prima folosire

Ce face late

Cu null safety, o variabilă de tip String trebuie să aibă mereu o valoare. late îi spune analizorului: „promit că o setez înainte s-o citesc”. Dacă promisiunea nu este respectată, la rulare apare LateInitializationError.

A doua folosire este inițializarea leneșă: late final x = calculScump(); nu rulează calculul la declarare, ci doar prima dată când citești x. Dacă nu-l citești niciodată, calculul nu se face deloc.

late este util pentru câmpuri setate după constructor (de exemplu în initState în Flutter) sau pentru variabile globale costisitoare. Nu-l folosi doar ca să scapi de erori: de multe ori un tip nullabil (String?) este alegerea corectă.

Exemple

Exemplul 1: Inițializare leneșă

Mesajul „Calculez…” apare abia la prima citire a lui raport, nu la declarare. A doua citire nu mai recalculează.

String genereazaRaport() {
  print('Calculez raportul...');
  return 'Raport: 28 de elevi, media 8,45';
}

void main() {
  late final raport = genereazaRaport();
  print('Programul a pornit.');
  print(raport);
  print(raport);
}

Rezultat

Programul a pornit.
Calculez raportul...
Raport: 28 de elevi, media 8,45
Raport: 28 de elevi, media 8,45

Exemplul 2: Câmp setat după constructor

conexiune nu are valoare la creare, ci după apelul lui porneste().

class Aplicatie {
  late String conexiune;

  void porneste(String server) {
    conexiune = 'conectat la $server';
  }
}

void main() {
  final app = Aplicatie();
  app.porneste('db.dexblog.ro');
  print(app.conexiune);
}

Rezultat

conectat la db.dexblog.ro

Exemplul 3: Citire înainte de inițializare

Dacă citești o variabilă late fără valoare, Dart aruncă LateInitializationError.

class Elev {
  late String clasa;
}

void main() {
  final e = Elev();
  try {
    print(e.clasa);
  } on Error catch (eroare) {
    print('${eroare.runtimeType}: $eroare');
  }
  e.clasa = 'a XI-a B';
  print('Acum: ${e.clasa}');
}

Rezultat

LateError: LateInitializationError: Field 'clasa' has not been initialized.
Acum: a XI-a B

Greșeli frecvente

  • late folosit peste tot ca să tacă analizorul: mută eroarea de la compilare la rulare.
  • late final setat de două ori: a doua atribuire aruncă LateInitializationError: Field has already been initialized.
  • Să uiți că inițializarea leneșă rulează la prima citire: dacă funcția are efecte (afișări, scrieri), ele apar mai târziu decât te aștepți.

Comenzi înrudite

  • final: Declară o variabilă care primește valoarea o singură dată și nu mai poate fi reatribuită.
  • null safety (? ! ?? ??=): Tipurile nu pot fi null decât dacă au ?; operatorii !, ?? și ??= lucrează cu valorile care pot lipsi.
  • var: Declară o variabilă care se poate modifica; tipul este dedus automat din valoarea inițială.