Sound null safety menjadikan pertanyaan apakah sebuah nilai boleh tidak ada sebagai bagian dari sistem tipe Dart. Jawabannya ditulis langsung pada deklarasi variabel, sehingga setiap kode yang berpotensi membaca null secara tidak sengaja ditolak sebelum program dijalankan. Topik ini membahas perbedaan String dan String? sebagai dua dunia tipe, aturan yang ditegakkan analyzer, serta promosi tipe setelah pemeriksaan null. Pemahaman ini menjadi fondasi bagi topik tentang operator null-aware, operator bang, dan late.
Dua dunia tipe pada null safety#
Sejak Dart 2.12, setiap tipe memiliki dua bentuk. Bentuk pertama adalah tipe non-nullable, yaitu tipe yang menjamin nilainya selalu ada sehingga null tidak pernah dapat disimpan ke dalamnya. Bentuk kedua adalah tipe nullable, yaitu tipe yang juga menerima nilai null. Penanda tanda tanya pada akhir nama tipe membentuk versi nullable, sehingga String dan String? diperlakukan sebagai dua tipe yang berbeda meskipun keduanya menyimpan teks. Tanda tanya itu merupakan bagian dari nama tipe, bukan pengubah nilai, sehingga String? dibaca sebagai satu tipe utuh yang mencakup null.
Perbedaan kedua tipe itu terlihat langsung pada deklarasi variabel. Variabel bertipe non-nullable wajib memiliki nilai awal yang nyata, sedangkan variabel bertipe nullable boleh dideklarasikan tanpa nilai dan otomatis bernilai null. Program berikut menunjukkan kedua bentuk deklarasi tersebut beserta keluarannya.
void main() {
String nama = "Ali";
String? julukan;
print("nama: $nama");
print("julukan: $julukan");
print("panjang nama: ${nama.length}");
}# menjalankan program dari folder topik
dart run dua-dunia.dartnama: Ali
julukan: null
panjang nama: 3Keluaran menegaskan perilaku kedua variabel. julukan yang dideklarasikan tanpa nilai awal tercetak sebagai null, dan pencetakan itu sah karena tipe String? memang mengizinkan null. Sebaliknya, nama hanya dapat dideklarasikan dengan nilai teks yang nyata. Akses anggota seperti nama.length juga tidak memerlukan pemeriksaan apa pun karena sistem tipe telah menjamin nama tidak pernah null.
Diagram berikut merangkum hubungan kedua tipe tersebut beserta arah penugasan yang diizinkannya.
Aturan yang ditegakkan analyzer#
Analyzer adalah komponen Dart SDK yang memeriksa kode secara statis sebelum program dijalankan. Pada null safety, analyzer menjadi penjaga dua aturan utama. Pertama, null tidak boleh ditugaskan ke variabel bertipe non-nullable. Kedua, anggota seperti length tidak boleh diakses tanpa pemeriksaan pada nilai yang bertipe nullable. Pelanggaran atas kedua aturan itu berhenti pada tahap pemeriksaan, jauh sebelum program sempat berjalan.
Berkas berikut sengaja memuat dua pelanggaran tersebut, yaitu penugasan null ke variabel String dan akses length pada variabel String? tanpa pemeriksaan. Perintahnya menggunakan dart analyze sehingga penolakan analyzer terlihat apa adanya.
# membuat berkas yang berisi dua pelanggaran aturan null safety
mkdir -p /tmp/uji/tipe-nullable
cat > /tmp/uji/tipe-nullable/ditolak.dart <<'EOF'
void main() {
String nama = null;
print(nama);
String? julukan;
print(julukan.length);
}
EOF
# memeriksa berkas dengan analyzer
dart analyze /tmp/uji/tipe-nullable/ditolak.dartAnalyzing ditolak.dart...
error - ditolak.dart:2:17 - A value of type 'Null' can't be assigned to a variable of type 'String'. Try changing the type of the variable, or casting the right-hand type to 'String'. - invalid_assignment
error - ditolak.dart:6:17 - The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!'). - unchecked_use_of_nullable_value
2 issues found.Analisis menemukan dua error dengan kode invalid_assignment dan unchecked_use_of_nullable_value. Pesan pertama menolak penugasan null ke variabel nama karena tipe String tidak mengizinkan null. Pesan kedua menolak akses length pada julukan yang bertipe String?, karena nilai itu berpotensi null. Kedua pesan menawarkan jalan keluar yang spesifik, mulai dari mengubah tipe variabel, menggunakan akses kondisional ?., hingga menambahkan pemeriksaan !.
Promosi tipe dan batasannya#
Pemeriksaan null memengaruhi cara sistem tipe membaca kode di dalam blok pemeriksaan. Setelah kondisi label != null terpenuhi, variabel label yang semula bertipe String? diperlakukan sebagai String di dalam blok tersebut. Mekanisme ini disebut promosi tipe (type promotion) dan dijalankan oleh analisis alur (flow analysis), yaitu kemampuan compiler melacak keadaan variabel pada setiap titik eksekusi.
Program berikut memanfaatkan promosi tipe pada parameter fungsi. Tidak ada operator tambahan yang diperlukan di dalam blok if, karena pemeriksaan null sudah mengubah perlakuan tipe di dalamnya.
String formatLabel(String? label) {
if (label != null) {
return label.toUpperCase();
}
return "tanpa label";
}
void main() {
print(formatLabel("catatan"));
print(formatLabel(null));
}# menjalankan program dari folder topik
dart run promosi.dartCATATAN
tanpa labelPromosi tipe memiliki batasan yang perlu dipahami sejak awal. Variabel lokal dan parameter dapat dipromosikan, sedangkan anggota kelas publik tidak. Batasan ini muncul karena anggota publik dapat diganti oleh subkelas atau diubah dari tempat lain, sehingga compiler tidak dapat menjamin nilainya tetap sama antara pemeriksaan dan penggunaan. Berkas berikut menunjukkan batasan tersebut, yaitu pemeriksaan null sudah dilakukan tetapi akses anggota di dalam bloknya tetap ditolak.
# membuat berkas yang memeriksa anggota publik sebelum mengaksesnya
mkdir -p /tmp/uji/tipe-nullable
cat > /tmp/uji/tipe-nullable/promosi-tidak.dart <<'EOF'
class Kartu {
String? isiPublik;
}
void main() {
final kartu = Kartu();
if (kartu.isiPublik != null) {
print(kartu.isiPublik.length);
}
}
EOF
# memeriksa berkas dengan analyzer
dart analyze /tmp/uji/tipe-nullable/promosi-tidak.dartAnalyzing promosi-tidak.dart...
error - promosi-tidak.dart:8:27 - The property 'length' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?.') or adding a null check to the target ('!'). - unchecked_use_of_nullable_value
- 'isiPublik' refers to a public property so it couldn't be promoted. See http://dart.dev/go/non-promo-public-field at promosi-tidak.dart:2:11.
1 issue found.Baris catatan pada keluaran menjelaskan penyebabnya, yaitu isiPublik merupakan anggota publik sehingga tidak dapat dipromosikan. Cara yang lazim untuk kasus seperti ini adalah menyalin nilai ke variabel lokal terlebih dahulu, kemudian memeriksa dan mengakses variabel lokal tersebut. Selain itu, bidang privat yang dinyatakan final dapat dipromosikan sejak Dart 3.2, sehingga anggota semacam itu juga bebas diakses setelah pemeriksaan null. Dengan demikian, penyalinan ke variabel lokal menjadi pola yang aman untuk semua bentuk anggota, sedangkan bidang privat final menawarkan jalan yang dikenali compiler secara langsung.
Ringkasan#
StringdanString?adalah dua tipe yang berbeda. Hanya tipe dengan penanda?yang menerima null.- Variabel non-nullable wajib memiliki nilai awal yang nyata, sedangkan variabel nullable otomatis bernilai null.
- Analyzer menolak penugasan null ke tipe non-nullable serta akses anggota tanpa pemeriksaan pada tipe nullable.
- Promosi tipe bekerja pada variabel lokal dan parameter, tetapi tidak pada anggota kelas publik.
Referensi#
- Sound null safety — dart.dev — Ringkasan resmi fitur null safety Dart beserta perubahannya pada sistem tipe.
- Understanding null safety — dart.dev — Latar dan rancangan analisis alur yang menjadi dasar null safety.
- Variables — dart.dev — Aturan deklarasi variabel beserta perilaku nilai awal pada Dart.