1 poin oleh GN⁺ 2025-10-05 | 1 komentar | Bagikan ke WhatsApp
  • Membandingkan perbedaan dan karakteristik yang muncul saat menyelesaikan masalah Advent of Code dengan dua bahasa, Ada dan Rust
  • Menganalisis perbedaan desain bahasa dan cara penulisan program nyata pada kedua bahasa yang berfokus pada keamanan dan keandalan
  • Perbedaan tampak dari berbagai sudut pandang seperti library standar, apakah fitur tersedia secara bawaan, perbedaan performa, serta gaya penanganan error
  • Menjelaskan contoh konkret yang ditemui saat benar-benar menulis dan mengoperasikan kode, seperti modularitas, generic, loop, dan penanganan error melalui contoh kode praktis
  • Perbedaan pengalaman pengembangan terlihat jelas dari perbedaan pada cara pengetikan statis, pemrosesan array, dan antarmuka penanganan error

Pengenalan dan tujuan

  • Saat menyelesaikan masalah Advent of Code (selanjutnya disebut AoC), penulis awalnya hanya menggunakan Ada, lalu sejak 2023 juga menulis solusi dengan Rust dan Modula-2 sehingga bisa membandingkannya secara langsung
  • Ketika memindahkan solusi yang sebelumnya berpusat pada Ada ke Rust, penulis merasakan perbedaan struktural dan pendekatan khas dari kedua bahasa tersebut
  • Tujuannya adalah memperjelas perbedaan penggunaan nyata dari sudut pandang keamanan kode, keandalan, dan desain bahasa

Versi bahasa yang digunakan untuk perbandingan

  • Ada 2022 (sebagian aturan Spark 2014 dirujuk bila diperlukan)
  • Rust 2021 (untuk perbandingan utama berbasis Rust 1.81.0)

Fitur yang dikecualikan dan kriteria perbandingan

  • Fitur representatif dari masing-masing bahasa (= fitur andalan) disebutkan secara singkat sebagai komentar di dalam pembahasan
  • Ada pula beberapa fitur yang tidak dibahas, bergantung pada pengalaman pribadi dan kebutuhan nyata dari masing-masing solusi
  • Sebisa mungkin menghindari opini pribadi dan berfokus pada karakteristik utama

Latar belakang dan sudut pandang penulis

  • Sebagai pengguna nonpenutur asli untuk Ada maupun Rust, dasar pengalaman penulis berasal dari bahasa era 1980-an seperti C/C++, Pascal, dan Modula-2
  • Akibatnya, gaya kode yang digunakan bisa berbeda dari gaya modern atau idiomatik
  • Implementasinya mungkin bukan yang paling optimal, dan tergantung situasi masalah, terkadang dipilih solusi yang intuitif atau tidak lazim

Posisi Ada dan Rust

  • Hingga kini Ada tetap menjadi bahasa untuk pengembangan sistem/embedded yang sangat aman dan andal, dengan penekanan pada keterbacaan kode
  • Rust memiliki kekuatan pada keamanan memori dan system programming, serta selama bertahun-tahun terpilih sebagai ‘bahasa yang paling disukai’ dalam survei pengembang Stack Overflow
  • Ada adalah bahasa tingkat tinggi serbaguna yang menawarkan spektrum yang kuat untuk pembacaan dan pemeliharaan kode
  • Rust berorientasi pada pengembangan program sistem tingkat rendah, dengan budaya pemrograman aman berbasis manajemen memori eksplisit serta tipe error/option

Perbandingan keamanan dan karakteristik struktural

  • Ada

    • Standar ISO (spesifikasi ketat)
    • Mudah mendeklarasikan tipe yang sesuai dengan karakteristik masalah (rentang, jumlah digit, dan sebagainya)
    • Indeks array boleh tidak berupa angka
    • Ada spesifikasi yang lebih ketat bernama Spark
  • Rust

    • Spesifikasi berpusat pada dokumentasi resmi (Reference) dan compiler
    • Deklarasi tipe bergantung pada tipe mesin (misalnya f64, u32)
    • Pengindeksan array secara alami hanya cocok untuk tipe numerik

Ringkasan utama tabel fitur/ketersediaan bawaan

  • Ada perbedaan pada dukungan seperti pengecekan rentang array, container generic, konkurensi, loop berlabel, dan pattern matching
  • Ada menggunakan penanganan error berbasis Exception (pengecualian), sedangkan Rust menggunakan pendekatan berbasis nilai balik melalui tipe Result/Option
  • Rust menonjol dalam dukungan macro, pattern matching, dan kemurnian fungsional
  • Ada mendukung desain berbasis kontrak serta verifikasi compile-time DBC (Design By Contract) melalui Spark
  • Dari sisi keamanan memori, Rust dan Spark menerapkannya secara paksa, sementara Ada tetap memperbolehkan penggunaan pointer Null

Perbandingan performa dan waktu eksekusi

  • Secara umum Rust dikenal cepat saat runtime tetapi lambat saat kompilasi, sedangkan Ada sebaliknya dikenal cepat saat kompilasi dan agak lebih lambat saat runtime tergantung pengecekan verifikasi
  • Hasil benchmark menunjukkan bahwa pada masalah day24, Rust mengalami overflow karena keterbatasan tipe f64, sedangkan Ada memungkinkan penentuan tipe tingkat tinggi seperti digits 18, sehingga dapat memilih tipe mesin secara otomatis, menghindari overflow, dan menunjukkan performa unggul
  • Rust perlu menggunakan f128 yang belum stabil atau library eksternal, sedangkan Ada dapat unggul hanya dengan penentuan tipe yang sesuai dengan spesifikasi compiler

Pemrosesan file dan penanganan error (Studi Kasus 1)

Pemrosesan file di Ada

  • Secara default menggunakan Ada.Text_IO
  • Membuka file secara eksplisit, membaca per baris, serta menangani Line berdasarkan rentang atau posisi yang diinginkan secara relatif intuitif
  • Saat terjadi error, penanganannya berupa exception alih-alih pesan error yang jelas, dan kemungkinan terjadinya error tidak tampak pada signature fungsi

Pemrosesan file di Rust

  • Menggunakan std::fs::File dan BufReader
  • Saat membuka file, hasil dikembalikan sebagai tipe Result, sehingga kemungkinan error terlihat jelas
  • Tidak mendukung akses indeks karakter secara langsung, dan harus diproses melalui Iterator
  • Berpusat pada alat fungsional dan iteratif seperti map, filter, collect, sum, serta mendukung berbagai macro (misalnya include_str!)
  • Error dinyatakan secara eksplisit pada tipe nilai balik, sehingga kejelasan propagasi error di tingkat fungsi dapat dijaga

Modularitas dan generic (Studi Kasus 2)

Modularitas di Ada

  • Pemisahan yang jelas antara spesifikasi (antarmuka) dan implementasi berbasis package
  • Untuk memperkuat modularisasi, digunakan subpackage dan kombinasi sintaks use/rename guna menyesuaikan keterbacaan
  • Dukungan generic pada package: dapat menggeneralisasi tipe/konstanta/seluruh subpackage

Modularitas di Rust

  • Modul disusun dengan sistem mod/crate, dan pemisahan spesifikasi serta implementasi diotomatisasi oleh pembuat dokumentasi
  • Penentuan akses pub/private memberikan kontrol akses yang deklaratif
  • Menggunakan use/as untuk kombinasi impor/pergantian nama
  • Dukungan pengujian bawaan memungkinkan deklarasi modul tes langsung di dalam kode, lalu dibangun dan dijalankan otomatis

Generic

  • Ada hanya mendukung generic pada tingkat package/procedure (tidak mendukung tipe tunggal secara langsung)
  • Rust dapat menerapkan generic langsung pada tipe (berbasis template)
  • Ada dapat mengekspresikan karakteristik tambahan seperti rentang tipe secara jelas melalui range type dan subtype, sedangkan Rust memanfaatkan konstanta instans

Perbandingan tipe enumerasi (Studi Kasus 3)

  • Ada mendukung deklarasi ringkas sekaligus secara otomatis mendukung penggunaan diskret, berurutan, loop iteratif, dan indeks
  • Deklarasi enum Rust juga mirip, tetapi pendekatan seperti pattern matching dan iterasi memerlukan cara yang lebih eksplisit

Kesimpulan

  • Dalam hal tipe spesifikasi tingkat tinggi, kemampuan verifikasi, dan pengecekan saat eksekusi, Ada memberikan kontrol yang lebih ketat
  • Dalam hal gaya pemrograman fungsional, pemrograman macro, dan penanganan error dengan bantuan compiler, Rust unggul dalam kemudahan pengembangan sekaligus keamanan
  • Dalam penyelesaian masalah nyata, Ada memiliki kekuatan pada kompatibilitas dengan kode lama dan pemeliharaan, sedangkan Rust unggul pada ekosistem alat pengembangan modern serta dukungan keamanan/paralelisme

1 komentar

 
GN⁺ 2025-10-05
Komentar Hacker News
  • Sangat disayangkan bahwa meskipun Ada punya banyak ide yang benar-benar bagus, bahasa ini kebanyakan hanya dipakai di bidang yang sangat menekankan keselamatan. Khususnya, fitur untuk membatasi rentang nilai pada tipe numerik sangat berguna untuk mencegah bug tertentu. Spark Ada juga mudah dipelajari dan mudah diterapkan dalam pengembangan perangkat lunak yang mematuhi SIL 4 (standar keselamatan perangkat lunak paling ketat). Selama beberapa dekade terakhir, industri perangkat lunak melaju dengan pola “pertumbuhan dulu, stabilitas belakangan”, tetapi sekarang terasa ada arus untuk kembali ke pengembangan perangkat lunak yang aman. Harapannya, pelajaran tentang keselamatan yang sudah terkumpul selama ini bisa melahirkan bahasa yang lebih baik. Kenyataannya, ide-ide bagus sering tersembunyi lalu hilang di dalam bahasa-bahasa minor
    • Jika lama berkecimpung di pengembangan perangkat lunak, akan terasa bahwa “menemukan ulang roda” itu benar-benar sering terjadi. Ada dan Rust sama-sama mirip dalam mengejar keselamatan, tetapi definisi dan cakupan penerapannya berbeda. Rust mengejar bentuk keselamatan penting yang sangat terfokus dengan sangat kuat, sedangkan Ada punya definisi keselamatan yang lebih luas dan konkret. Saat saya belajar Ada di awal 90-an, kritik yang paling umum adalah bahwa bahasanya terlalu besar dan kompleks sehingga memperlambat pengembangan (waktu itu compiler Ada 83 yang tervalidasi harganya sekitar 20 ribu dolar per orang dalam nilai uang sekarang). Namun zaman berubah, dan orang-orang kini mengakui bahwa bahasa besar dan kompleks seperti Rust memang dibutuhkan untuk pemrograman konkuren yang benar-benar aman
    • Nim juga mendukung subrange untuk membatasi rentang nilai tipe, terinspirasi dari Ada dan Modula
      type
        Age = range[0..200]
      
      let ageWorks = 200.Age
      let ageFails = 201.Age
      
      Saat kompilasi, akan muncul error bahwa 201 tidak bisa dikonversi ke tipe Age
      Tautan penjelasan Nim Subranges
    • Ada (berdasarkan GNAT) mendukung analisis satuan/dimensi fisik saat compile time, yaitu pengecekan unit. Ini sangat praktis di lapangan teknik, jadi saya heran mengapa bahasa lain hanya menyediakan fitur sepenting ini lewat library pihak ketiga
      Dokumen terkait
    • Di C++ juga mudah membuat tipe numerik dengan rentang nilai terbatas lewat kode (meskipun tidak ada di standard library, implementasinya sendiri sangat mudah). Beberapa pengecekan keselamatan bisa dilakukan saat compile time, bukan runtime. Akan bagus jika semua bahasa mendukung fitur seperti ini secara standar
    • Hal yang paling saya sesalkan dari Ada adalah pendekatannya yang jelas terhadap object-oriented programming (OOP). Kebanyakan bahasa memasukkan konsep OOP ke dalam satu paket bernama “class”, tetapi Ada memungkinkan message passing, dynamic dispatch, subtyping, generic, dan lainnya diterapkan secara terpisah sesuai kebutuhan. Saya sangat suka bagaimana masing-masing fitur itu berpadu dengan rapi
  • Penulis menyebut perbedaan seperti Ada punya spesifikasi resmi sedangkan Rust tidak, tetapi dari sudut pandang pengguna, yang lebih penting daripada itu adalah adopsi bahasa/ekosistemnya (tooling, library, komunitas). Ada memang sukses di bidang kedirgantaraan/keselamatan dan cocok untuk AOC atau pekerjaan low-level embedded, tetapi dalam proyek nyata (sistem terdistribusi, komponen OS, dan sebagainya), faktor seperti format data, protokol, dukungan IDE, dan kolaborasi dengan rekan kerja punya porsi yang jauh lebih besar. Pada akhirnya, saat pertama memilih bahasa, aspek lingkungan seperti inilah yang paling menentukan
    • Baru-baru ini Rust juga menerima dokumen spesifikasi dari Ferrocene yang mengambil referensi dari gaya spesifikasi Ada. Dokumennya terbuka, jadi bisa dijadikan rujukan
      Spesifikasi Rust
    • Baik Rust maupun Ada lemah jika dilihat sebagai “spesifikasi formal” dalam arti ketat, yaitu dokumen yang bisa dibuktikan secara mekanis. Bahkan Spark Ada pun berdiri di atas asumsi semantik bahasa, dan itu sendiri belum sepenuhnya formal serta belum dalam bentuk yang bisa dibaca mesin
    • Para pengembang perangkat lunak kendali pesawat pun kemungkinan akan menjawab, “Kalau ini memang tidak penting di lingkungan dunia nyata, maka ya benar, proses kami memang berlebihan.” Memang di bidang yang kritis terhadap keselamatan, bahasa dan proses yang ketat seperti Ada justru merupakan standar
  • Menarik bahwa walaupun Ada kalah dalam beberapa fitur terkait tipe dibanding Rust, dalam hal keterbacaan kode Ada justru sering lebih unggul. Tulisan perbandingan itu tidak menyinggung kecepatan compiler, dan kesan bahwa Ada adalah bahasa yang rumit mungkin lebih merupakan cerita masa lalu; jika dibandingkan dengan Rust sekarang, belum tentu begitu. Setelah membaca ini, saya jadi ingin mencoba proyek sungguhan dengan Ada
    • Saya penasaran apa tepatnya yang dimaksud dengan “kelemahan terkait tipe”. Dalam pengalaman saya, sistem tipe Ada sangat ekspresif. Ada tipe rentang nilai buatan pengguna, array yang bisa diindeks dengan enumerasi arbitrer, definisi operator per tipe, serta beragam fitur tambahan pada tipe seperti pengecekan compile/runtime, precondition, postcondition, dan lain-lain. Ada juga discriminated record, representation clause untuk struct, dan sebagainya. Bukan kelemahan, malah kemampuan yang sangat kuat
  • Saya ingin membahas perbedaan string di Ada dan Rust. Saat dirancang pada awal 1980-an, Ada menjadikan array char sebagai “string”, sehingga mudah diindeks seperti array byte biasa. Rust sejak awal dirancang dengan kesadaran terhadap Unicode, jadi string di Rust pada dasarnya adalah teks sungguhan yang dikodekan dalam UTF-8. Karena itu, Ada memungkinkan random indexing seperti array, sedangkan di Rust konsep string-nya berbeda sehingga ada pilihan untuk mengubahnya menjadi array byte biasa
    • String Unicode bawaan di Ada umumnya berupa array UTF-32. Berbeda dengan Rust, Ada tidak menyediakan literal UTF-8 secara langsung, melainkan harus dikonversi dari array 8/16/32-bit
    • String Rust juga bisa diindeks. Hanya saja, Rust tidak memperlakukan string sebagai array biasa dan lebih sering menggunakan slice substring. Jika pemotongan dan pengindeksan dilakukan di tengah karakter tertentu, akan terjadi panic (kasus yang melanggar batas nilai encoding Unicode). Untuk kasus seperti AoC yang selalu hanya memakai ASCII, lebih tepat memakai slice byte lewat [u8] atau metode str::as_bytes
  • Pernyataan penulis bahwa Rust “tidak mendukung pemrograman konkuren secara bawaan” terasa aneh. Rust punya fitur thread yang tertanam di bahasa, dan justru lebih mudah dipakai daripada async. Ini hanya menjadi masalah jika membutuhkan sangat banyak thread sampai menabrak batas sumber daya; untuk sebagian besar perangkat lunak, thread bawaan sudah cukup
    • (Sebagai non-pengguna Rust, saya benar-benar penasaran) Saya ingin tahu bagaimana penanganan cancel di thread dan async di Rust berbeda, dan bagaimana bedanya dengan async di bahasa lain. Di C++, Python, dan C#, pengelolaan pembatalan pada async jauh lebih baik daripada thread. Saya dengar di Rust pengelolaan cancel/interruption justru agak lebih sulit karena tidak ditangani lewat exception, jadi saya penasaran dengan pengalaman nyata di lapangan. Saya juga ingin tahu bagaimana penanganan interupsi seperti ini di Ada
    • Saya penasaran di titik mana scheduler work-stealing seperti Tokio benar-benar lebih cepat daripada sekadar menjalankan beberapa thread. Saya merasa ini mirip dengan array sederhana (misalnya VecMap) yang cepat saat jumlah elemen kecil, tetapi setelah melewati jumlah tertentu struktur data lain jadi lebih efisien. Saya ingin tahu pada titik praktis mana work-stealing mulai menguntungkan
    • Secara realistis, alasan utama memakai Async adalah karena crate pihak ketiga yang digunakan memang Async. (Misalnya: Reqwest membutuhkan Tokrio) Dalam pengembangan aplikasi level tinggi, kalau memaksa hanya non-Async, pada akhirnya akan menemui batas
    • Di lingkungan platform dengan dukungan thread yang lemah (WASM, embedded, dan sebagainya), Async justru lebih cocok. Situasi ratusan ribu orang mengakses blog secara bersamaan itu tidak realistis, jadi rasanya berlebihan jika kebutuhan Async dibenarkan terutama dengan skenario seperti itu
  • Menarik mengetahui bahwa Ada juga punya compiler open source. Dulu saya mengira semuanya compiler proprietari, jadi saya sama sekali tidak melirik Ada, tetapi sekarang rasanya perlu dicek lagi
    • Compiler GNAT sudah dirilis lebih dari 30 tahun lalu, dan dulu sempat ada kesalahpahaman bahwa karena tidak ada GPL runtime exception maka hasil kompilasinya juga harus GPL, tetapi sekarang isu itu sudah terselesaikan
    • GNAT dibuat berbasis GCC sejak tahun 90-an, dan di beberapa universitas pernah langsung dipakai untuk mata kuliah yang berfokus pada praktik seperti pemrograman real-time. Saya juga pernah mencoba memakai Ada sebagai bahasa pengantar belajar pemrograman, tetapi segera beralih ke Pascal lalu C++
  • Di bidang 3D printing, salah satu proyek yang menarik perhatian saya belakangan ini adalah board kontrol printer dan firmware bernama Prunt. Firmware-nya dikembangkan dengan Ada, dan itu pilihan yang cukup unik tetapi secara konsep terasa cocok
    Situs Prunt
    Prunt GitHub
  • Di akhir Case Study 2 tertulis, “Jika klien perlu mengetahui SIDE_LENGTH, tambahkan fungsi yang mengembalikannya”, tetapi sebenarnya alih-alih fungsi, cara yang lebih langsung adalah memakai deklarasi konstanta seperti pub const SIDE_LENGTH: usize = ROW_LENGTH;
  • Saya tidak setuju dengan klaim bahwa kedua bahasa sama-sama mendorong pemrograman yang berpusat pada stack. Ada justru secara aktif mendorong alokasi statis
  • Saya cukup heran array index Ada dengan tipe arbitrer diperkenalkan seolah keunggulan besar. Hampir semua bahasa punya dictionary (hash map) di standard library, dan Rust bahkan menyediakan dua jenis
    • Yang dimaksud di sini adalah array bawaan bahasa. Misalnya, di Ada indeks array “eggs” bisa ditetapkan sebagai tipe BirdSpecies, sehingga eggs[Robin], eggs[Seagull], dan seterusnya valid, tetapi eggs[5] tidak diizinkan. Di Rust juga bisa dibuat struktur data yang diinginkan (misalnya dengan implementasi Index<BirdSpecies>) sehingga eggs[Robin] valid dan eggs[5] jadi error. Hanya saja, Rust tidak mendukung ini langsung sebagai “array” di tingkat bahasa. Ketika seperti di Ada “tipe buatan pengguna bisa dideklarasikan sebagai integer yang merupakan subset”, pengindeksan seperti ini benar-benar menunjukkan nilainya. Di Rust, integer dengan rentang terbatas yang murni buatan pengguna seperti itu belum bisa dibuat (yang ada hanya jenis internal seperti NonZeroI16). Akan sangat bagus kalau Rust mendukung sampai level ini
    • Ada juga memiliki dukungan bawaan untuk hash map dan set. Standar terkait container Ada (lihat bagian A.18). Kemampuan memakai rentang “nilai berurutan” yang khas (misalnya 0~N-1) sebagai tipe indeks array adalah keunggulan besar dibanding dictionary dalam situasi yang membutuhkan dense map atau akses memori berurutan, karena jauh lebih cepat dan juga lebih efisien terhadap cache
    • Pembatasan subtype untuk tipe indeks array di Ada secara struktur adalah konsep yang sepenuhnya berbeda dari dictionary. Di tingkat bahasa, jenis nilai yang boleh menjadi indeks array pun bisa dibatasi