Back to IF3210 Pengembangan Aplikasi Piranti Bergerak
Dart Null Safety and Type System
Questions/Cues
- Apa perbedaan fundamental antara
finaldanconstyang sering membingungkan?- Kapan menggunakan tipe
Objectvsdynamicdan apa risikonya?- Bagaimana operator
?.,??,??=, dan!bekerja secara konkret?- Apa itu kata kunci
latedan masalah apa yang dipecahkannya?- Mengapa sound null safety dianggap memberi keuntungan performa di production?
Reference Points
- IF3210 Pengembangan Aplikasi Piranti Bergerak (Slides 13b: 3-14)
final vs const: Perbedaan yang Kritis
finaldanconstsama-sama mencegah reassignment, tetapi memiliki semantik yang sangat berbeda:
Aspek finalconstWaktu evaluasi Runtime Compile-time Kedalaman immutability Referensi saja (shallow) Seluruh objek (deep) Isi objek Bisa berubah Tidak bisa berubah Canonicalization Tidak Ya (satu salinan di memori) Contoh valid final list = [1,2,3]; list.add(4);const list = [1,2,3]; // list.add(4) ERROR
finalberarti variabel hanya memiliki satu referensi — tidak bisa diarahkan ke objek lain — tetapi objek yang dirujuk masih dapat dimutasi.constberarti seluruh objek bersifat deeply immutable dan dikompilasi sebagai nilai tetap.Canonicalization: dua instans
constdengan nilai yang sama adalah objek yang identik di memori (dapat diverifikasi denganidentical()). Ini berarti Dart hanya membuat satu salinan untuk semua widgetconstyang identik, yang menjadi alasan utama mengapa widgetconstdirekonstruksi lebih cepat dalam Flutter.Immutable Classes dengan const Constructor
Untuk membuat class yang seluruh instansnya bersifat deeply immutable, definisikan const constructor dengan semua field bertipe
final:
- Semua instance fields wajib
final- Konstruktor dideklarasikan dengan kata kunci
const- Instans yang dibuat dengan
const MyClass(...)dijamin identik jika parameternya sama (identical()mengembalikantrue)Pola ini umum digunakan di Flutter untuk widget dan data classes yang tidak perlu berubah, mengoptimalkan proses rebuild tree widget.
Object vs dynamic: Keamanan Tipe
Dart menyediakan dua tipe “super” yang tampak serupa tetapi berperilaku sangat berbeda:
Object: supertype dari semua tipe non-nullable di Dart. PenggunaanObjecttetap diperiksa oleh kompiler saat compile-time — hanya method yang ada di classObjectyang bisa dipanggil tanpa cast. Ini memberikan keamanan tipe penuh.dynamic: menonaktifkan seluruh pemeriksaan tipe Dart. Operasi apapun diperbolehkan oleh kompiler, tetapi error tipe muncul saat runtime (bukan compile-time).dynamicibarat “lepas sabuk pengaman” — berbahaya jika tidak digunakan dengan hati-hati.Prinsipnya: gunakan
Object(atau generics) kapanpun memungkinkan; gunakandynamichanya saat benar-benar diperlukan (misalnya saat berinteraksi dengan data JSON yang belum diketahui strukturnya).Pengecekan dan Konversi Tipe
Dart menyediakan beberapa mekanisme untuk bekerja dengan tipe secara aman:
is/is!: operator pengecekan tipe yang mengembalikanbool. Setelahischeck, Dart secara otomatis mempromosikan tipe variabel (type promotion) dalam blok tersebut.as: type cast eksplisit. Akan melemparTypeErrorsaat runtime jika objek bukan tipe yang dimaksud — gunakan hanya jika yakin tipenya.int.parse(String): mengkonversiStringkeint. MelemparFormatExceptionjika string tidak valid..toString(): mengkonversi nilai apa pun ke representasiString-nya..toInt()/.toDouble(): konversi antar tipe numerik (tersedia dinum,int,double).Null-Aware Operators
Sound null safety di Dart didukung oleh sekumpulan operator null-aware yang membuat penanganan nilai
nulllebih ringkas dan aman:
Operator Nama Perilaku ?.Null-conditional obj?.method()— panggilmethod()hanya jikaobjtidak null; kembalikannulljikaobjnull??Null-coalescing expr ?? default— kembalikanexprjika tidak null, ataudefaultjika null??=Null-aware assignment x ??= value— assignvaluekexhanya jikaxsaat ini null!Null assertion obj!— beritahu kompiler bahwaobjpasti tidak null; melemparNull check operator used on a null valuesaat runtime jika salahKata Kunci late
latememungkinkan deklarasi variabel non-nullable yang diinisialisasi setelah deklarasi, bukan saat deklarasi. Ini mengatasi dua masalah umum:
- Inisialisasi yang mahal (lazy initialization): variabel
latetidak diinisialisasi sampai pertama kali diakses, menghemat sumber daya jika variabel mungkin tidak pernah digunakan.- Field yang diinisialisasi di luar konstruktor: misalnya field yang baru bisa diset setelah
super()selesai, atau dalam callbackinitState()di Flutter.Jika variabel
latediakses sebelum diinisialisasi, Dart melemparLateInitializationErrorsaat runtime.Sound Null Safety: Manfaat dan Cara Kerja
Sejak Dart 3.0, sound null safety adalah perilaku bawaan yang tidak bisa dinonaktifkan. Semua variabel secara default tidak bisa bernilai
null— untuk variabel nullable, harus ditambahkan sufiks?pada tipenya (contoh:String?,int?).Manfaat utama sound null safety:
- Eliminasi null checks di runtime: kompiler tahu variabel non-nullable tidak akan pernah null, sehingga tidak perlu menyisipkan pemeriksaan null saat runtime, menghasilkan kode yang lebih efisien.
- Optimasi caching: karena kompiler dapat membuktikan nilai tertentu tidak akan pernah null, ia bisa mengoptimalkan bagaimana nilai tersebut disimpan dan diakses.
- Bug terdeteksi lebih awal:
NullPointerExceptionyang biasanya hanya muncul saat runtime kini menjadi error kompiler yang muncul saat pengembangan.
finaldanconstberbeda fundamental:finalhanya mengunci referensi (shallow) dievaluasi saat runtime, sedangkanconstmengunci seluruh objek (deep, compile-time) dan memungkinkan canonicalization (satu instans di memori untuk nilai identik).Objectmempertahankan keamanan tipe compile-time;dynamicmenonaktifkannya dan berisiko error runtime. Sound null safety menjadikan semua variabel non-nullable secara default — tipe nullable ditandai dengan?. Operator?.(akses aman),??(nilai default),??=(assign jika null), dan!(null assertion) memperlancar penanganan null. Kata kuncilatemendukung lazy initialization dan inisialisasi di luar konstruktor. Secara keseluruhan, null safety menggeser deteksi bug dari runtime ke compile-time dan memungkinkan optimasi performa oleh kompiler.
Additional Information
Null Safety dan Migrasi Kode Lama
Proyek Dart yang ditulis sebelum null safety dapat dimigrasikan menggunakan tool
dart migrate. Proses ini menganalisis kode dan menyarankan anotasi?dan!yang tepat. Selama masa transisi, kode lama (pre-null-safety) dan baru bisa hidup berdampingan menggunakan language version markers, meskipun ini tidak lagi relevan untuk proyek baru yang menggunakan Dart 3.Tipe Never dan Void
Dart memiliki dua tipe khusus lainnya:
Neveradalah tipe bawah (bottom type) yang merepresentasikan nilai yang tidak pernah ada — fungsi yang selalu melempar exception dideklarasikan bertipeNever.voidmenandakan bahwa nilai kembalian tidak boleh digunakan (berbeda dariNull), umumnya dipakai sebagai return type fungsi yang hanya menimbulkan efek samping.Pattern Matching di Dart 3
Dart 3 memperkenalkan pattern matching yang bekerja bersama null safety. Pola seperti
if (value case String s) { ... }tidak hanya mengecek tipe tetapi sekaligus mendestrukturisasi dan mempromosikan variabel. Ini membuat kode penanganan tipe heterogen jauh lebih ekspresif.Proyek Eksplorasi Mandiri
- Buat class dengan
const constructordan verifikasi canonicalization menggunakanidentical()— bandingkan dengan class yang hanya menggunakanfinal- Eksperimen dengan
dynamicvsObject: tulis fungsi yang menerima keduanya, coba panggil method yang tidak ada, dan amati kapan error muncul (compile-time vs runtime)- Implementasikan semua empat null-aware operators dalam satu program kecil yang mensimulasikan pengambilan data pengguna yang mungkin null
Bacaan Lanjutan
- Dokumentasi Resmi Dart: “Understanding null safety” (dart.dev/null-safety/understanding-null-safety)
- Dart: “Sound null safety” (dart.dev/null-safety)
- Blog Dart: “Announcing Dart 3” — penjelasan perubahan null safety di Dart 3
- “Effective Dart: Usage” — panduan kapan menggunakan
dynamicsecara bertanggung jawab