Null safety əsasları
Sound null safety-də tip sistemi iki qrupa bölünür: non-nullable T və nullable T?. String name heç vaxt null ola bilməz — bunu compiler zəmanət verir, ona görə çağırış yerində yoxlamaya ehtiyac qalmır. String? name isə null ola bilər və compiler ondan istifadə etməzdən əvvəl yoxlamanı tələb edir.
"Sound" sözü burada mühümdür: yoxlama həm compile-time-da aparılır, həm də runtime-da tip məlumatı buna uyğun gəlir — nəticədə compiler null yoxlamalarını tam silə bilir və kod daha sürətli olur. Bu, TypeScript-in strictNullChecks-indən fərqlidir: orada yoxlama yalnız compile-time-dadır.
Praktik nəticə: null xətası artıq "runtime sürprizi" deyil, dizayn qərarı olur. Sahə T?-dirsə, bu, "bu dəyər həqiqətən yox ola bilər" deməkdir və sən bunu şüurlu seçmisən.
| Operator | Nə edir | Nümunə |
|---|---|---|
| `?.` | Null-aware çıxış — obyekt `null`-dırsa, nəticə `null` | `user?.name` |
| `??` | Default dəyər — sol tərəf `null`-dırsa sağı qaytarır | `name ?? 'Qonaq'` |
| `??=` | Yalnız `null` olduqda mənimsədir | `cache ??= compute();` |
| `!` | Bang — "bu `null` deyil" iddiası; səhvdirsə runtime-da atır | `user!.name` |
| `?..` | Null-aware cascade | `user?..save()..log()` |
| `?[]` | Null-aware indeks | `list?[0]` |
Flow analysis və promotion. Compiler kodun axınını izləyir: if (name != null) blokunun içində name artıq String? yox, String kimi davranır — buna type promotion deyilir. ?. və ! yazmağa ehtiyac qalmır.
Promotion həm də erkən qayıtma ilə işləyir: if (name == null) return; sətrindən sonra qalan bütün kodda name promote olunmuş sayılır. Bu, "guard clause" üslubunu Dart-da xüsusilə səmərəli edir.
Promotion işləməyən hallar da var və interview-da məhz onlar soruşulur:
- Public sahələr — nə
finalolmayan instans sahəsi, nə dəgetterpromote olunmur; publicfinalsahə də olunmur, çünki alt sinif onugetterkimi override edə bilər - Top-level və static dəyişənlər
- Closure-də dəyişdirilən lokal dəyişənlər
Səbəb: compiler yalnız aralıqda dəyişməyəcəyinə zəmanət verə bildiyi dəyəri promote edir. Public sahə üçün belə zəmanət yoxdur — arada başqa metod onu dəyişə bilər, alt sinif isə onu getter kimi override edə bilər və getter hər çağırışda fərqli dəyər qaytarır.
Bir istisna var: Dart 3.2-dən private `final` sahələr (final String? _token;) promote olunur, çünki compiler bütün kitabxananı görür və sahənin override oluna bilmədiyinə əmindir. Praktik nəticə: modeli private final sahələr üzərində qursan, ! operatoruna ehtiyac özü-özünə azalır.
`!` operatoru nə vaxt dizayn iyidir? Bang compiler-ə "mən daha yaxşı bilirəm" demək deməkdir. Bəzən doğrudan da bilirsən (məsələn, dərhal yuxarıda yoxlanmış lokal dəyər), amma kodda ! sıxlığının artması adətən modelin səhv olduğunu bildirir.
Tipik səbəblər və düzgün həllər:
- Sahə
T?-dir, çünki konstruktorda hazır deyil → `late final` və ya iki ayrı state sinfi - Sahə
T?-dir, çünki bəzi hallarda mövcud olmur → `sealed` iyerarxiya ilə halları ayır - Dəyər
nullgəlirsə default lazımdır → `??` - Sahədən oxuyub istifadə edirsən → lokal dəyişənə köçür (
final n = this.name; if (n != null) ...)
Praktikada komandalar avoid_null_checks_in_equality_operators və oxşar lint-lərlə yanaşı, code review qaydası kimi "yeni ! üçün şərh tələb olunur" prinsipini tətbiq edir.
Interview ipucu. "Nullable sahə niyə promote olunmur, lokal dəyişən isə olunur?" — bu, null safety mövzusunun ən çox verilən sualıdır və səthi cavab ("belədir") kifayət etmir. Güclü cavab səbəbi izah edir: "Compiler yalnız aralıqda dəyişməyəcəyinə zəmanət verə bildiyi dəyəri promote edir. Lokal dəyişən üçün bu zəmanət var. Sahə isə başqa metoddan dəyişdirilə bilər, `getter` hər çağırışda fərqli dəyər qaytara bilər, alt sinif onu override edə bilər — ona görə iki oxunuş arasında əlaqə yoxdur." Sonra iki praktik həlli göstər: final local = field; if (local != null) { ... } — bu, ! yazmadan promotion qazandırır; və sahəni private final etmək — Dart 3.2-dən belə sahələr promote olunur.
📚 Mənbələr və sənədlər
- Sound null safetyrəsmidart.dev
- Tip sistemirəsmidart.dev