- Dalam manajemen memori, Zig menawarkan pendekatan yang lebih sederhana dan intuitif dibandingkan Rust
- Borrow checker Rust memang kuat, tetapi untuk pengembangan alat CLI kecil, ia memicu kompleksitas berlebihan dan beban bagi pengembang
- Manajemen memori manual Zig memungkinkan tercapainya keamanan memori yang efisien hanya dengan alat yang tepat dan sedikit disiplin dari pengembang
- Keamanan program tidak hanya soal keamanan memori, tetapi juga dipengaruhi berbagai faktor seperti perilaku yang dapat diprediksi, kinerja yang mudah dikelola, dan perlindungan data
- Rust cocok untuk sistem berskala besar, tetapi untuk alat CLI kecil yang praktis, Zig lebih unggul dari sisi produktivitas pengembangan dan pemeliharaan
Gambaran umum
Belakangan ini, saat membuat alat CLI, saya cenderung memilih Zig lebih dulu daripada Rust
Dasar manajemen memori: stack dan heap
- Stack adalah area memori berukuran tetap yang cepat untuk menyimpan data yang sangat sementara seperti parameter fungsi, variabel lokal, dan alamat pengembalian
- Heap adalah area untuk alokasi memori dinamis, digunakan ketika umur data lebih panjang atau ukurannya ditentukan saat runtime
- Stack secara struktural sederhana tetapi ruangnya terbatas, sedangkan heap punya lebih banyak hal yang perlu diperhatikan dari sisi kecepatan dan fragmentasi
Borrow Checker Rust
- Borrow checker Rust menjamin keamanan memori pada waktu kompilasi
- Dengan menegakkan aturan seperti referensi, kepemilikan, dan lifetime, ia mencegah sejak awal kesalahan seperti dereferensi null pointer dan dangling pointer
- Namun, keamanan memori hanya diperiksa berdasarkan waktu kompilasi, dan ini tidak serta-merta menghilangkan kesalahan pengguna atau masalah rancangan kepemilikan yang rumit itu sendiri
Contoh: Notes CLI buatan saya
- Saat mencoba menulis CLI untuk mengelola catatan pribadi dengan Rust, saya harus bersusah payah merancang ulang strukturnya karena borrow checker
- Sebaliknya, di Zig, hanya dengan memakai allocator, pembuatan indeks berbasis pointer serta perubahan/penghapusan secara bebas bisa dilakukan jauh lebih sederhana
- Borrow checker Rust punya tujuan yang jelas, tetapi dengan Zig, hanya dengan pengetahuan dasar manajemen memori dan sedikit disiplin, tingkat efisiensi dan keamanan yang tinggi tetap bisa dicapai
Keamanan alat CLI tidak berhenti pada keamanan memori
- Keamanan sejati sebuah produk mencakup banyak unsur seperti perilaku yang dapat diprediksi, umpan balik yang bermakna saat terjadi kesalahan, perlindungan data sensitif, dan ketahanan terhadap serangan
- Baik Rust maupun Zig tidak bisa disebut “aman” jika selain keamanan memori, syarat-syarat lain ini tidak terpenuhi
- Misalnya, jika CLI diam-diam menimpa data saat terjadi error atau salah mengatur izin file, pengguna bisa mengalami masalah serius
-
Keamanan alat CLI
- Perilaku yang dapat diprediksi: perlu menjamin perilaku yang konsisten dan jelas meski ada input salah atau situasi tak terduga
- Pencegahan crash dan kerusakan data: error harus ditangani dengan baik, serta perlu mencegah kerusakan data atau crash yang tak terinformasikan
- Pengelolaan kinerja: meski memproses data dalam jumlah besar, tidak boleh terjadi pemborosan sumber daya atau penurunan responsivitas
- Perlindungan informasi sensitif: perlu berhati-hati terhadap file sementara dan pengaturan izin
- Ketahanan terhadap serangan: perlu kuat terhadap validasi input, memory overflow, serangan injeksi, dan sejenisnya
Kekuatan dan keterbatasan Borrow Checker Rust
-
Kekuatan
- Memblokir data race dan referensi ganda: compiler menjamin aturan satu mutable reference dan banyak immutable reference
- Jaminan compile-time yang kuat: sebagian besar bug terkait memori diblokir sebelum program dijalankan
- Menemukan bug lebih awal: ini menjadi keuntungan besar pada layanan produksi atau sistem konkurensi
-
Keterbatasan dan ketidaknyamanan
- Cognitive overhead: bahkan untuk pekerjaan CLI kecil, pengembang tetap harus memikirkan kepemilikan/lifetime/manajemen referensi
- Boilerplate/distorsi struktural: wrapper seperti Rc, RefCell, penggunaan
cloneberlebihan, dan perancangan ulang struktur membuat fokus bergeser dari “memecahkan masalah” ke “memuaskan compiler” - Lemah terhadap bug logis/keadaan: hanya menjamin aturan memori; tidak menjamin prediktabilitas, kesalahan logika, atau integritas data
- Kompleksitas edge case: benturan lifetime mudah terjadi pada cache, state global, mutable index, dan sebagainya
- Akibatnya, pada proyek CLI kecil, borrow checker Rust menjadi “pajak mental” bagi pengembang dan dapat membuat segalanya lebih rumit daripada yang sebenarnya diperlukan
Pendekatan Zig terhadap keamanan dan kesederhanaan
- Zig berbasis pemeriksaan keamanan opsional dan manajemen memori manual
- Konsep allocator sudah tertanam sehingga penggunaan memori yang terstruktur dan dapat diprediksi bisa diimplementasikan
- Kita juga bisa membuat allocator kustom untuk menentukan cara pengelolaan memori yang sesuai dengan karakteristik proyek
- Berkat sintaks
deferdi Zig, pelepasan otomatis dan pembersihan resource saat scope berakhir juga jauh lebih intuitif - Tidak seperti Rust, Zig lebih menekankan tanggung jawab pengembang sehingga dibutuhkan disiplin, tetapi jika dirancang dengan baik, keamanan memori lebih mudah dicapai dan dipertahankan
- Zig menghasilkan kode yang ringkas, dan perubahan struktur seperti pointer, list, dan indeks jauh lebih sederhana dibanding Rust
- Tanpa merasa terikat seperti di Rust, tingkat keamanan dan efisiensi kode yang setara tetap bisa diwujudkan
- Selain itu, fitur comptime Zig sangat membantu untuk eksekusi kode, pengujian, dan optimasi pada waktu kompilasi
Pentingnya pengalaman pengembang (Developer Ergonomics)
- Pengalaman pengembang (ergonomics) mencakup unsur-unsur seperti sintaks bahasa, tooling, dokumentasi, hingga komunitas
- Rust pada akhirnya menjamin keamanan memori berkat aturan yang sangat ketat, tetapi aturan yang berlebihan dan ceremony justru menurunkan produktivitas
- Zig menekankan desain yang digerakkan pengembang sehingga kode lebih mudah dan cepat ditulis, diubah, serta dipahami
- Dengan kode yang intuitif, iterasi yang cepat, dan beban mental yang rendah, Zig membuat pengembang fokus memecahkan masalah tanpa harus bertarung dengan alat
- Zig mempercayai pengembang dan memberi alat serta pilihan yang tepat, sedangkan Rust bisa terasa terlalu mengawasi dan membatasi
- Alih-alih “melindungi pengembang dari kesalahan”, lingkungan yang ramah pengembang adalah yang menjamin kesempatan untuk belajar dan berkembang melalui kesalahan sendiri
Kesimpulan
- Untuk bidang seperti sistem besar, multithread, dan berjalan lama, tempat keunggulan Rust benar-benar maksimal, Rust tetap merupakan pilihan terbaik
- Namun, untuk alat CLI kecil dan praktis, ringannya Zig, kesederhanaannya, serta cepatnya implementasi dan pemeliharaan lebih cocok
- Keamanan memori hanyalah satu bagian dari teka-teki keamanan, dan unsur penting bagi alat CLI seperti perilaku yang dapat diprediksi, kemudahan pemeliharaan, dan ketangguhan lebih mudah dicapai di Zig
- Pada akhirnya, yang penting bukanlah ‘bahasa yang lebih baik’, melainkan workflow yang cocok untuk saya dan ‘pemilihan alat’ yang sesuai dengan karakteristik proyek
- Zig adalah bahasa yang sangat pas untuk pengembangan alat kecil karena menggabungkan "keamanan memori + biaya mental rendah + keramahan/p produktivitas bagi pengembang"
3 komentar
Sepertinya ekosistemnya masih belum se-stabil Rust.
Karena Zig cukup sering mengalami breaking change di versi-versi barunya... jadi sepertinya meskipun proyeknya kecil, sebaiknya tetap dipasangi CI agar bisa terus dikelola.
Opini Hacker News
Kelebihan Zig adalah memungkinkan kita tetap berpikir seperti developer C, meski sampai batas tertentu ini juga cuma soal kebiasaan
Developer yang sudah cukup terbiasa dengan Rust tidak lagi “berkelahi” dengan borrow checker, karena mereka sudah berpikir dengan struktur kode seperti itu
Pendekatan seperti “object soup” di Rust memang tidak terlalu cocok, tetapi sebenarnya itu bukan berarti pendekatan itu secara fundamental lebih mudah, hanya terasa mudah karena kita sudah terbiasa
Jika menerima premis bahwa ergonomics (pengalaman penggunaan) sulit diukur atau dikuantifikasi, diskusi seperti ini akan terus terasa kabur
“Berkelahi dengan borrow checker” berasal dari masa ketika orang baru memahami lifetime leksikal di Rust
Dalam pengalaman saya, developer Rust yang mahir sering menaburkan Arc di mana-mana dan praktis memakainya seperti garbage collection otomatis
Saya juga sering melihat proyek Rust open source yang ditulis developer berpengalaman tetap memakai Arc, Clone, Copy, dan semacamnya di banyak tempat
Kelebihan Zig adalah kita bisa mengembangkan secara familier seperti di C sambil tetap mendapat fitur keamanan dari bahasa dan tooling
Saya tidak setuju dengan sebagian besar isi tulisan aslinya
Rust, sama seperti C atau Zig, tetap membuat kita memikirkan lifetime, ownership, dan borrow scope; bedanya adalah ada atau tidaknya bantuan compiler
Manusia, secerdas apa pun, tetap bisa membuat kesalahan saat lelah atau terdistraksi, dan mengakui itu justru adalah kebijaksanaan
Ruang program yang dianggap aman oleh compiler Rust tidak cukup luas, sehingga cukup sering menolak program yang sebenarnya valid
Contoh: jika pada struct Foo,
bardanbazmasing-masing adalah string, lalubardiambil sebagai mutable reference danbazsebagai immutable reference, itu tidak akan terkompilasi, sehingga kita terpaksa mengakali struktur kode dalam situasi seperti iniSebagai sanggahan, harus mengubah kode ke desain yang kualitasnya urutan kedua atau ketiga hanya untuk “menghindari kasus ketika kondisi sebenarnya aman tetapi kompilasi ditolak” itu sendiri adalah beban besar
Contoh di atas tampaknya benar-benar kasus yang sangat bagus, saya ingin bertanya apakah boleh membahasnya di blog atau artikel saya
Setelah melihat kode di atas, justru saya jadi makin tidak yakin dengan klaim tersebut
Kita perlu ingat bahwa tidak semua program harus se-“aman” itu
Kita tumbuh sambil menikmati banyak perangkat lunak Unsafe, seperti Star Fox 64, MS Paint, dan FruityLoops
Saya juga pernah membaca bahwa pencipta Zig, Andrew Kelley, membuat Zig karena tidak ada lingkungan pengembangan untuk perangkat lunak produksi musik (DAW), dan saya rasa Zig cocok untuk perangkat lunak kreatif semacam itu
Siapa pun yang sensitif terhadap bug memori bisa memakai Rust
Saya bahkan percaya Super Mario World jadi lebih seru karena bug memori
“Aman” adalah kependekan dari “program saya berjalan sesuai yang saya maksudkan”
unsafe)Saya agak bingung, apakah alasan orang menganggap komentar saya buruk adalah karena mereka menafsirkannya seolah saya bilang keamanan memori tidak penting?
Saya merasa nilai borrow checker terlalu diremehkan
Borrow checker Rust menjamin akses memori yang tidak valid dicegah pada waktu kompilasi
Tentu ada ketidaknyamanan karena kita harus mengubah struktur kode agar sesuai aturan compiler
Saat saya memakai Rust sendiri, saya tidak pernah merasa lifetime annotation itu salah; memang terasa seperti chore yang merepotkan, tetapi cepat terbiasa
Selama tidak memakai
unsafe, di Rust dua thread tidak bisa menulis ke memori yang sama secara bersamaanSaya tidak terlalu setuju dengan klaim “mengapa Zig terasa lebih praktis untuk alat CLI”, karena Rust tetap punya keunggulan dalam mencegah CVE (kerentanan)
Dalam praktiknya, saya sendiri melakukan sebagian besar pekerjaan dengan bahasa GC, dan saat berkontribusi ke bahasa lain, saya tidak terlalu peduli apakah itu Rust, Zig, atau C/C++
Memangnya alat CLI itu istimewa?
Pernyataan bahwa tanpa
unsafedua thread tidak bisa menulis ke memori yang sama secara bersamaan juga tidak sepenuhnya sesederhana ituSaya setuju bahwa mengimplementasikan backlinks di Rust terlalu rumit
Itu bisa dilakukan dengan
Rc,Weak,RefCell,.borrow(), dan sebagainya, tetapi tidak mudahJika programnya berjalan singkat, alokasi arena juga bisa menjadi solusi, dan mungkin itulah yang dimaksud dengan alat CLI
Rust benar-benar menunjukkan kekuatannya pada aplikasi besar, multithread, dan berjalan lama
Saya sendiri pernah menulis klien metaverse besar dengan Rust, dan meski puluhan thread berjalan 24 jam, tidak ada kebocoran memori maupun crash
Jika hal yang sama dibuat dengan C++, tim QA dan alat seperti Valgrind akan menjadi keharusan, sementara bahasa skrip terlalu lambat dari sisi performa
Saya juga pernah membuat pesawat simulasi fisika dengan Rust yang bahkan memperhitungkan kelengkungan bumi dan variasi gravitasi
Zig memang menarik, tetapi D juga masih ada, dan secara pribadi saya merasa D adalah pengganti C/C++ yang saya inginkan
Sintaks Zig terasa agak canggung, dan Rust sudah menjadi pusat dalam ekosistem
Go juga punya pangsa besar di banyak alat bahasa, dan di bidang AI dipakai paling banyak setelah Python
Sebelum Rust, dulu ada perdebatan Go vs. D, dan saya bahkan sempat membeli buku D sebelum akhirnya beralih ke Go
int64juga terasa lebih intuitifD memang bagus, tetapi belum melahirkan killer app yang membuatnya benar-benar populer
Saya tidak terlalu paham mengapa kita harus bersikeras memakai Rust atau Zig untuk alat CLI
Bottleneck-nya ada di I/O, bukan karena GC lambat
Menurut saya isu GC bukan poin utama kecuali pada hal yang sangat intensif memori seperti game atau database
Saya ingin menekankan bahwa ketimbang berdebat soal keamanan memori, saya lebih memikirkan alasan memilih bahasa yang tidak memerlukan GC
Kalau alasannya “karena no-GC itu menyenangkan”, itu sendiri sudah cukup, tidak perlu diperdebatkan
Waktu startup yang instan, tanpa jeda eksekusi, sangat bermanfaat
Membuat CLI dengan Go terasa sangat baik, meski saya sendiri tidak terlalu menyukai bahasa Go
Saya memprioritaskan bahasa yang punya sum type, pattern matching, dan dukungan async
Soal pernyataan bahwa pengembangan tanpa GC hanya relevan untuk dunia game
Perdebatan soal GC ini terasa seperti bandwagon
Saya membuat alat catatan sederhana dengan borrow/referencing bawaan Rust, dan ternyata tidak serumit yang dibayangkan
Jika kita membayangkan struktur yang menyimpan indeks daftar
noteslalu menghubungkannya lewat map, perbedaan kecepatannya nyaris tidak ada dan juga tidak punya kelemahan keamananKalaupun salah indeks, itu akan tertangkap sebagai error out-of-range, yang jauh lebih baik daripada menimpa memori kernel
Bahkan saat printf debugging pun itu terasa jauh lebih mudah dan intuitif
Raw pointer atau reference biasanya hanya saya pakai di tempat yang benar-benar perlu seperti allocator atau async runtime; untuk logika umum, pendekatan berbasis indeks lebih cocok
Ini juga terkenal sebagai alasan async Rust tidak bisa memakai self-referential struct, sehingga muncul isu terkait
PinPointer ke nilai yang disimpan di
vecakan menjadi tidak valid jika terjadi realloc dan sejenisnya, dan dalam kasus seperti ini Miri akan langsung memberi errorSebagai developer C++, jika saya mencari bahasa yang aman, saya merasa Swift paling cocok
Bahasa yang terasa familier atau mirip memang lebih cepat diadaptasi
Dukungan lintas platform Swift juga belakangan makin kuat, dan ada beberapa orang dari komite standar C++ yang ikut terlibat
Namun, karena keterkaitannya dengan Apple dan tidak adanya framework UI native, ekspansinya di luar ekosistem Apple relatif lebih terbatas
Saya berharap Swift bisa menjadi lebih populer
Kalau ada sumber yang membandingkan Swift dengan Zig/C, saya akan senang jika direkomendasikan
Ada yang bilang Zig juga bisa dipakai membuat perangkat lunak yang aman dari sisi memori dengan kehati-hatian yang cukup, tetapi sebenarnya C pun bisa mencapai hasil serupa jika dipakai dengan disiplin
Pada akhirnya, “sedikit disiplin (latihan)” inilah yang dalam kenyataan sering kurang, dan di situlah masalah muncul
Zig juga secara tambahan menyelesaikan masalah-masalah berikut
comptime, serta build time yang puluhan kali lebih cepat daripada C++/Rust juga menjadi kekuatan besarJika C sudah gagal selama lebih dari 50 tahun dalam masalah discipline seperti ini, berarti ini sesuatu yang lebih sulit daripada sekadar “jalan Shaolin”