1 poin oleh GN⁺ 2025-06-04 | 1 komentar | Bagikan ke WhatsApp
  • Pengulangan if err != nil di Go telah lama menjadi keluhan besar dalam survei pengguna selama bertahun-tahun, tetapi tim Go memutuskan untuk sementara tidak mendorong perubahan sintaks penanganan error
  • Proposal check/handle pada 2018, try pada 2019, dan ? pada 2024 semuanya gagal mencapai konsensus yang memadai, dan khususnya try memicu penolakan kuat karena alur kontrol yang tersembunyi
  • Dalam prosedur proposal Go, jika tidak ada konsensus umum maka proposal biasanya ditolak, dan bahkan di antara anggota senior tim Go di Google saat ini tidak ada suara bulat mengenai arah terbaik
  • Pihak yang mendukung status quo menilai Go sudah memiliki cara penanganan error yang berfungsi, dan sintaks baru akan menimbulkan biaya besar pada gaya kode, debugging, dokumentasi, tooling, dan kode yang sudah ada
  • Tim Go akan menutup proposal terbuka dan proposal baru yang terutama menargetkan sintaks penanganan error tanpa penyelidikan tambahan, dan akan fokus pada peluang perbaikan lain sampai ada pemahaman masalah yang lebih jelas

Keluhan lama yang dibuat oleh if err != nil

  • Salah satu keluhan paling lama di Go adalah kepanjangan kode penanganan error
  • Pola representatifnya berbentuk seperti berikut
x, err := call()
if err != nil {
    // handle err
}
  • Dalam program dengan banyak pemanggilan API dan error yang hanya dikembalikan begitu saja, if err != nil dapat mendominasi sisa kode
  • Pada fungsi contoh printSum, dari 10 baris isi fungsi, baris yang tampak sebagai pekerjaan sebenarnya hanya 4 baris termasuk pemanggilan, output, dan return, sedangkan 6 baris sisanya tampak seperti kebisingan
  • Dalam survei pengguna tahunan Go, penanganan error selama bertahun-tahun menjadi keluhan teratas; untuk sementara ketiadaan generics mengunggulinya, tetapi setelah Go mendukung generics, penanganan error kembali menjadi keluhan teratas

Tiga proposal sintaks utama

  • Upaya eksplisit pertama tim Go dimulai pada 2018 sebagai bagian dari upaya Go 2, ketika Russ Cox merangkum masalahnya secara resmi
  • Rancangan desain oleh Marcel van Lohuizen didasarkan pada mekanisme check dan handle, serta mencakup analisis pendekatan bahasa lain dan alternatif
func printSum(a, b string) error {
    handle err { return err }
    x := check strconv.Atoi(a)
    y := check strconv.Atoi(b)
    fmt.Println("result:", x + y)
    return nil
}
  • Pendekatan check/handle dinilai terlalu kompleks, dan pada 2019 muncul proposal try yang lebih sederhana
    • Kata kunci mirip check menjadi fungsi bawaan try
    • Bagian handle dihilangkan
    • Dibuat alat tryhard untuk mengubah kode penanganan error yang ada ke gaya try
    • Issue GitHub terkait diperdebatkan dengan sengit hingga hampir 900 komentar
func printSum(a, b string) error {
    // use a defer statement to augment errors before returning
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x + y)
    return nil
}
  • try memengaruhi alur kontrol dengan cara mengembalikan dari fungsi yang melingkupinya saat terjadi error, dan karena return bisa terjadi bahkan di dalam ekspresi yang bersarang dalam, banyak pengguna merasa sulit menerimanya
  • Saat itu, memperkenalkan kata kunci baru mungkin akan lebih baik, dan sekarang versi bahasa dapat dikendalikan lebih rinci melalui file go.mod dan direktif per file
  • Proposal terbaru dari Jimmy Frasche mengikuti arah kembali ke desain check/handle semula sambil menangani sebagian kelemahannya

Refleksi prosedur setelah try dan proposal ?

  • Setelah proposal try, Russ Cox meninjau kembali proses proposal melalui seri “Thinking about the Go Proposal Process”
  • “Go Proposal Process: Large Changes” menilai bahwa try seharusnya menjadi rancangan desain kedua, bukan proposal dengan jadwal implementasi
  • Selama beberapa tahun setelah itu, tim Go tidak mendorong perubahan sintaks penanganan error, sementara di komunitas terus masuk proposal yang serupa, menarik, sulit dipahami, atau tidak layak diwujudkan
  • Ian Lance Taylor membuat umbrella issue yang merangkum status proposal perbaikan penanganan error, dan Go Wiki juga dibuat untuk mengumpulkan umpan balik dan diskusi terkait
  • “go error handling proposals” oleh Sean K. H. Liao melacak banyak proposal penanganan error selama bertahun-tahun
  • Karena keluhan terus berlanjut, Ian Lance Taylor pada 2024 mengumumkan proposal untuk mengurangi boilerplate penanganan error dengan ?
    • Notasi itu dipinjam dari operator ? di Rust
    • Dalam studi pengguna informal skala kecil, sebagian besar peserta menebak dengan benar arti kode Go yang menggunakan ?
    • Juga dibuat alat untuk mengubah kode Go umum ke sintaks baru dan prototipe compiler
func printSum(a, b string) error {
    x := strconv.Atoi(a) ?
    y := strconv.Atoi(b) ?
    fmt.Println("result:", x + y)
    return nil
}
  • Proposal ini juga dengan cepat dibanjiri banyak komentar dan usulan perubahan detail berbasis preferensi, lalu Ian menutup proposal tersebut dan memindahkan isinya ke discussion
  • Versi yang sedikit direvisi mendapat reaksi yang agak lebih positif, tetapi tetap tidak memperoleh dukungan luas

Mengapa sekarang ingin berhenti

  • Tim Go menilai bahwa untuk masa depan yang dapat diperkirakan, mereka harus berhenti mencoba menyelesaikan masalah sintaks penanganan error
  • Proses proposal mendukung keputusan ini
    • Tujuan proses proposal adalah mencapai konsensus umum atas hasil secara tepat waktu
    • Jika konsensus umum tidak ditemukan dalam diskusi issue tracker, proposal biasanya ditolak
    • Jika tidak ditemukan konsensus maupun langkah berikutnya, arsitek Go akan meninjau diskusi dan mencoba mencapai konsensus internal
  • Tidak ada proposal penanganan error yang mendekati dukungan berbasis konsensus, dan semuanya ditolak
  • Bahkan anggota senior tim Go di Google pun tidak bulat tentang arah terbaik ke depan, dan tanpa konsensus yang kuat mereka tidak dapat melanjutkan secara masuk akal

Argumen untuk status quo dan perubahan

  • Di pihak status quo, ada alasan praktis berupa kematangan Go dan biaya ekosistem
    • Jika Go sejak awal memperkenalkan sugar sintaks khusus untuk penanganan error, perdebatan sekarang mungkin akan lebih kecil, tetapi Go sudah berusia 15 tahun dan telah memiliki cara penanganan error yang berfungsi
    • Bahkan jika solusi sempurna ditemukan sekarang, situasinya bisa berubah dari pendukung perubahan yang tidak puas menjadi pendukung status quo yang tidak puas
    • Generics tidak wajib ditulis langsung oleh pengguna, tetapi sintaks baru untuk penanganan error bisa membuat kode terlihat tidak idiomatis jika tidak dipakai, sehingga pada praktiknya hampir semua orang harus menggunakannya
    • Menambahkan sintaks baru juga bisa bertentangan dengan aturan desain Go yang tidak menyediakan banyak cara untuk melakukan hal yang sama
  • Fitur redeklarasi pada deklarasi variabel singkat := diperkenalkan untuk menyelesaikan masalah yang timbul karena penanganan error
    • Tanpa redeklarasi, setiap pemeriksaan error berurutan akan memerlukan nama err yang berbeda atau deklarasi variabel terpisah
    • Jika saat itu sudah ada dukungan sintaks yang lebih baik untuk penanganan error, aturan redeklarasi dan kompleksitas terkait mungkin tidak diperlukan
  • Jika error diperkaya dan ditangani dengan benar, porsi pengulangan sederhana akan berkurang
    • Dalam survei pengguna ada masukan berulang bahwa error tidak memiliki stack trace
    • Dimungkinkan memakai fungsi pembantu untuk membuat dan mengembalikan error yang telah diperkaya
    • Menambahkan informasi input seperti fmt.Errorf("invalid integer: %q", a) membuat proporsi relatif boilerplate menjadi lebih kecil
  • Fitur pustaka standar juga dapat mengurangi boilerplate penanganan error
    • Ini sejalan dengan “Errors are values” oleh Rob Pike
    • Dalam beberapa kasus, beberapa error dapat ditangani sekaligus dengan cmp.Or
  • Menulis, membaca, dan debugging adalah aktivitas yang berbeda
    • Menulis pemeriksaan error berulang memang membosankan, tetapi penyelesaian kode berbantuan IDE dan LLM dapat dengan mudah menghasilkan pemeriksaan error dasar
    • Saat membaca, kepanjangan lebih menonjol, dan IDE dapat menyediakan toggle untuk menyembunyikan kode penanganan error
    • Saat debugging, keberadaan pernyataan if terpisah memudahkan penambahan println atau pemasangan breakpoint
    • Jika penanganan error disembunyikan di balik check, try, atau ?, sering kali perlu dikembalikan ke bentuk if biasa, dan proses ini dapat memperumit debugging atau menimbulkan bug halus
  • Perubahan bahasa membawa biaya bukan hanya pada desain dan implementasi, tetapi juga pada perubahan kode yang ada, pembaruan dokumentasi, dan penyesuaian tooling
    • Tim Go relatif kecil dan juga memiliki banyak prioritas lain yang harus ditangani
    • Prioritas dan ukuran tim bisa berubah
  • Sebagian pengguna Go yang ditemui tim Go di Google Cloud Next 2025 menyatakan dengan tegas bahwa bahasa ini tidak boleh diubah demi penanganan error yang lebih baik
    • Mereka mengatakan bahwa saat baru pindah dari bahasa lain, ketiadaan sintaks khusus penanganan error di Go memang paling menonjol, tetapi setelah menulis kode Go yang lebih idiomatis hal itu menjadi kurang penting
    • Sampel ini tidak cukup besar untuk representatif, tetapi bisa jadi merupakan kelompok yang berbeda dari orang-orang yang terlihat di GitHub
  • Argumen yang mendukung perubahan juga tetap berlaku
    • Ketiadaan dukungan penanganan error yang lebih baik tetap menjadi keluhan teratas dalam survei pengguna
    • Pendekatan yang hanya berfokus mengurangi jumlah karakter mungkin merupakan arah yang keliru
    • Jika penanganan error dasar dibuat mencolok secara visual lewat kata kunci sambil menghapus boilerplate err != nil, akan lebih mudah memeriksa dalam code review apakah error sudah ditangani
    • Masih belum cukup diketahui apakah inti masalahnya hanya kepanjangan sintaks, atau justru kepanjangan dari penanganan error yang baik saat menyusun error yang bermakna bagi API, developer, dan pengguna akhir

Keputusan tim Go

  • Sampai sekarang, tidak ada upaya untuk menangani penanganan error yang memperoleh momentum yang cukup
  • Tim Go menilai ada kekurangan pemahaman bersama atas masalah, dan bahkan tidak semua orang sepakat bahwa memang ada masalah sejak awal
  • Untuk masa depan yang dapat diperkirakan, mereka tidak akan mendorong perubahan bahasa tingkat sintaks untuk penanganan error
  • Proposal terbuka dan proposal yang akan datang yang terutama menargetkan sintaks penanganan error akan ditutup tanpa penyelidikan tambahan
  • Eksplorasi dan diskusi komunitas memang tidak berujung pada perubahan sintaks penanganan error, tetapi telah menghasilkan berbagai perbaikan pada bahasa Go dan prosesnya

1 komentar

 
GN⁺ 2025-06-04
Opini Hacker News
  • Kalau ingin melontarkan usulan ringan seperti “seharusnya tim Go melakukan ini saja”, sebaiknya lihat dulu halaman wiki yang ditautkan di artikel, https://go.dev/wiki/Go2ErrorHandlingFeedback, dan pencarian issue GitHub https://github.com/golang/go/issues?q=+is%3Aissue+label%3Aerror-handling
    Usulan yang hendak diajukan hampir pasti bukan yang pertama, dan kemungkinan besar banyak di antaranya sudah ditelaah secara mendalam
    Saya menyukai pendekatan terbuka seperti ini dari tim Go, dan sampai sekarang masih senang memakai Go setiap hari untuk pekerjaan

    • Draf desain yang menjadi dasar umpan balik menyebut C++, Rust, dan Swift, tetapi dalam dokumen umpan balik besar yang ditautkan itu saya tidak menemukan pendekatan seperti notasi do, for-comprehension, atau monadic-let yang dipakai di Haskell/Scala/OCaml
      Di beberapa halaman issue GitHub dengan komentar terbanyak pun saya tidak melihat hal serupa, dan rasanya berlebihan menganggap tim Go adalah penyihir desain bahasa sehingga solusi yang dilempar ringan oleh orang-orang di sini pasti sudah mereka pertimbangkan
      Tim Go melakukan kesalahan yang sama seperti Java, yaitu bahasa bertipe statis tanpa polimorfisme parameter, dan akar masalah penanganan error ini juga ada di sana, tetapi mereka tampak angkat tangan dan tidak memperbaikinya
    • Mengherankan bahwa meski orang-orang yang sangat pintar dan berpengalaman menulis halaman itu serta mendiskusikannya selama bertahun-tahun, solusi ala Haskell berupa monad Maybe/Either dan notasi do yang memakai operator bind sama sekali tidak terlihat
      Kedengarannya mungkin megah dan mengintimidasi, tetapi itu adalah cara yang elegan dan murni secara fungsional untuk meneruskan error sampai ke tempat yang bisa menanganinya tanpa membuatnya terlupakan
      Bagi orang yang menulis kode Haskell, cara ini sudah begitu mengakar, jadi sulit dipahami bahwa tidak ada orang di komunitas Go yang mengetahuinya dan menyukainya
      Saya berterima kasih atas halaman itu sendiri dan tautannya, tetapi terasa membingungkan bahwa orang-orang yang begitu peduli pada bahasanya melewatkan solusi yang sudah sangat mapan seperti ini
    • Mungkin jawabannya sudah ada di suatu tempat, tetapi saya penasaran mengapa ini menjadi masalah yang sangat sulit khususnya di Go
      Hampir semua bahasa punya cara masing-masing yang lebih baik, jadi saya ingin tahu apakah ini sekadar karena tidak bisa mengambil keputusan atau tidak bisa memuaskan semua orang, atau ada alasan konkret mengapa solusi dari bahasa lain tidak cocok untuk bahasa Go itu sendiri
    • Pola yang sering terlihat dalam kritik terhadap Go adalah orang-orang yang relatif amatir berasumsi bahwa pembuat Go tidak lebih paham bahasa pemrograman daripada mereka
      Kenyataannya, hampir selalu para pembuat Go tahu jauh lebih banyak
      Amatir secara naif mengira bahasa terbaik adalah yang dijejali fitur paling banyak, apalagi jika fitur itu sesuai selera mereka
      Ini mirip seseorang yang baru mulai belajar membuat pisau, lalu melihat pisau koki Jepang dan merasa ada yang kurang, kemudian berpikir pisau itu akan lebih baik jika diberi gagang cetak 3D dengan lekukan jari, kompartemen rahasia, korek api, dan speaker Bluetooth
    • Aneh juga masih disebut Wiki padahal sekarang untuk mengubahnya harus mendapat persetujuan
  • Buat saja daftar checklist, bahas dan isi tiap butirnya, lalu jangan keluarkan lagi kecuali ditemukan kesalahan semantik fatal atau celah soundness
    Setelah semuanya terisi, implementasikan, dan orang-orang yang ribut apakah harus ditulis .await, /await, atau .await!() akan menghilang lagi
    Rust berjalan seperti ini; beberapa issue memang tertunda lebih dari 10 tahun, tetapi akhirnya butir-butirnya terisi dan distabilkan dari nightly terbaru
    Kalau Go tidak bisa menyelesaikan satu masalah yang langsung dihadapi semua orang, padahal ada beberapa proposal matang, hanya karena tidak bisa memilih salah satunya dan menunggu bikeshedding berhenti, maka prosesnya itu komedi

    • Tidak ada yang namanya “ada beberapa proposal sempurna yang sudah selesai”
    • Begitulah cara Rust mendapat reputasi sebagai bahasa yang jelek dibaca dan sintaksnya tidak konsisten akibat desain ala komite
    • Bahasa pemrograman adalah sistem yang dirancang, sehingga harus masuk akal secara keseluruhan
      Ia bukan sekadar kumpulan fitur yang ditambahkan begitu memenuhi persyaratan checklist
    • Ingin memasang pengingat 25 tahun lagi
      Apakah Rust akan menjadi berantakan seperti C++? Apakah Go akan tetap menjadi bahasa yang tak lekang oleh waktu seperti saat dirilis?
    • Pernyataan “Go tidak bisa menyelesaikan satu masalah yang langsung dialami semua orang” itu aneh
      Dalam survei, persentase yang menyebut penanganan error adalah 13%, dan ada juga orang yang lebih menyukai cara yang sekarang apa adanya
      https://go.dev/blog/survey2024-h1-results
  • Dulu saya pernah menulis fungsi Go yang agak unik, yang mengharapkan fungsi internal mengembalikan error
    Jadi kalau fungsi internal tidak mengembalikan error, fungsi luar harus mengembalikan error dan melakukan penanganan lain; kalau fungsi internal mengembalikan error, fungsi luar harus mengembalikan nil
    Singkatnya, saya harus menulis if err == nil { // return an error }, bukan if err != nil { ... }, tetapi karena kebiasaan saya menulis yang pertama, dan butuh cukup lama untuk debug
    Karena saya sudah terlalu kebal terhadap if err != nil, otak saya sama sekali tidak mempertimbangkan kemungkinan bahwa konstruksi itu tidak boleh ada di sana
    Jadi menurut saya ekspresi yang umum memang perlu syntactic sugar. Kalau perbedaan antara if err != nil yang sangat umum dan if err == nil yang jarang itu lebih menonjol, itu benar-benar akan membantu

    • Setiap kali menulis if err == nil, saya menambahkan komentar // inverted agar lebih mencolok
      Akan bagus kalau ditangani di level bahasa, tetapi setidaknya saya membagikannya sebagai cara untuk membuatnya lebih terlihat
    • Tentu saja if fruit != "Apple" { ... } juga bisa menciptakan situasi yang sama
      Saya penasaran apakah ada solusi umum untuk memperbaiki ini, dan melihatnya sebagai masalah khusus penanganan error rasanya agak meleset
      Tidak ada yang istimewa atau unik pada error; itu hanya state seperti yang lain
    • Ini justru menjadi argumen yang menentang perubahan sintaks
      Kalau muncul pola umum if err == nil { return ... }, kali ini pola itulah yang akan bertebaran di kode
      Solusi saat ini sudah baik, dan tampaknya terutama orang yang baru mulai memakai Go atau masih pemula yang tidak menyukainya
      Di sekitar saya, orang menyukai penanganan error yang “verbose” karena eksplisit, jelas, dan mudah dibaca
    • Untuk menjadi devil’s advocate, IDE dan font bisa saja, hanya dalam mode sintaks Go, menyorot if err != nil seperti satu simbol ligatur kecil, atau merendernya samar sebagai latar
      Dengan begitu, bentuk yang berbeda persis dari string itu, seperti if err == nil, justru akan lebih menonjol
    • Poin yang bagus. Sepertinya ini juga bisa diselesaikan di editor dengan notasi terlipat seperti if err … {
  • Saya suka penanganan error eksplisit di Go
    Sebuah fungsi selalu berhasil, atau bisa berhasil maupun gagal. Fungsi yang selalu berhasil itu sederhana; jika fungsi yang bisa gagal ternyata gagal, kode di luarnya tidak bisa lanjut dalam keadaan gagal begitu saja, jadi harus menanganinya
    Di sini bahasa-bahasa mulai bercabang. Banyak bahasa melempar exception, menaikkannya sampai ada yang secara eksplisit menangkapnya, dan menyediakan semacam stack trace
    Di Go, saya suka bahwa saat menulis kode selalu ada pilihan yang harus diambil: mengabaikan error dan lanjut (foo, _ := doSomething()), mengembalikan lebih awal tanpa informasi bermakna (return nil, err), mengembalikan lebih awal dengan konteks yang berguna, atau menafsirkan error yang diterima lalu bercabang
    Misalnya, jika baris yang akan diperbarui tidak ditemukan di database, lapisan service bisa mengembalikan error not found dan API menjadi 404, atau fungsi delete yang idempoten bisa menafsirkan not found sebagai sukses
    Kalau Go 2 atau bahasa lain, saya ingin ada tipe Result ala Rust/Swift alih-alih tuple yang bisa nil, serta tipe error yang lebih bertipe dan bisa dienumerasi alih-alih selalu memakai error secara langsung
    Namun jika Result ditambahkan di atas pengembalian tuple idiomatis Go 1, akan ada banyak cara melakukan hal yang sama sehingga menimbulkan kebingungan dan perpecahan; karena itu lebih cocok untuk Go 2 atau bahasa baru

    • Berdasarkan pengalaman saya, kebijakan penanganan error harus didelegasikan kepada pemanggil
      Lapisan rendah dalam stack umumnya tidak tahu apa yang harus dilakukan, jadi tidak semestinya menangani error
      Kebijakan “menangani” error pada akhirnya mudah berubah menjadi kebijakan membungkus error lalu mengembalikannya lagi ke atas stack, dan itu menjadi pekerjaan remeh yang cukup banyak
    • “Jika fungsi gagal, kegagalan itu harus ditangani” justru titik di mana Go gagal
      Go memungkinkan error diabaikan sepenuhnya, dan hasilnya bisa berujung pada crash
      Agak sulit dimengerti bagaimana bisa seseorang menunjukkan dengan tepat syarat untuk membuat software yang tangguh, tetapi tetap menyukai cara Go menangani error
    • Saya berharap sintaks borgo[1] langsung menjadi bahasa Go 2. Boleh bermimpi
      [1]: https://borgo-lang.github.io/ | https://github.com/borgo-lang/borgo
    • Dengan kecepatan seperti ini, Go2 tampak seperti laboratorium ide yang tidak akan pernah dirilis
    • Saya ingin bertanya: bagus dibandingkan apa?
      Semua bahasa fungsional, banyak bahasa modern seperti Rust, bahkan Java dengan checked exception pun menyediakan ini
      Dalam bahasa yang punya generics, “penanganan error” ala Go umumnya bisa direplikasi, dan mungkin menghasilkan kode yang lebih baik
      Kalau jawabannya JavaScript atau Python, itu memang pola perbandingan yang umum
  • Untuk Go, ini keputusan yang tepat. Saat pertama kali mengenal Go saya tidak suka penanganan error-nya, tetapi sekarang saya benar-benar menyukainya
    Titik baliknya ada dua. Setelah membaca tulisan https://go.dev/blog/errors-are-values, saya benar-benar menerima sudut pandang “error adalah nilai”, dan di atas dasar itu saya juga membuat paket yang cukup populer, https://github.com/stytchauth/sqx
    Selain itu, saya perlahan terbiasa memakai panic(err) untuk state keliru yang benar-benar tidak masuk akal
    Tidak ada alasan memaksa kode induk menangani semua state ngawur yang bahkan tidak punya naluri untuk ditangani; satu atau dua panic yang ditempatkan dengan baik bisa menghapus ratusan pemeriksaan error dari codebase
    Misalnya, bayangkan persoalan seperti apakah ada logger default di dalam ctx

    • Sayang sekali. Kedua alasan yang diajukan tidak ada hubungannya dengan betapa buruknya penanganan error Go, dan membuat penanganan error lebih baik juga tidak akan memperburuknya
      Justru besar kemungkinan akan membaik
    • Bahkan PHP punya penanganan error yang lebih baik berkat level error dan operator @ untuk menekan error di titik pemanggilan
      bash juga punya -e
    • Saya juga suka cara Go. Saya rela menerima lebih banyak baris kode kalau itu membuat saya lebih yakin apa yang sedang terjadi
      Dulu saat pertama kali memakai C#, saya merasa pintar karena memahami alur try/catch/finally, using, nesting, apa yang terjadi kalau error muncul di catch, apa yang terjadi kalau muncul di finally
      Sekarang saya lebih suka tidak memikirkan hal-hal seperti itu
    • Sum type error ala Rust juga nilai
  • Saya tidak suka cara tulisan ini mengatakan bahwa masalah utama penanganan error di Go adalah sintaksnya terlalu bertele-tele. Itu tidak terlalu saya pedulikan
    Yang lebih penting adalah error bisa dibuang diam-diam atau terabaikan tanpa sengaja, hasil pemanggilan fungsi bukan sebuah nilai sehingga tidak mudah disimpan atau diteruskan, dan dibutuhkannya errors.Is, sebuah mekanisme runtime aneh di mana seluruh error “berlapis” tidak cocok dengan sistem tipe
    Switch untuk error juga sulit, standard library memakai nilai sentinel, dan interaksinya dengan generics buruk sehingga paket seperti errgroup jadi diperlukan
    Apakah ada lagi yang terlewat?

    • 90% waktu saya bekerja profesional dengan Go adalah memaksa membuat test case agar tiap cabang pengembalian error tercakup oleh statement coverage
      Dalam bahasa yang punya exception, tidak ada orang yang akan melakukan itu
    • Menurut saya, di mana pun tulisan ini tidak mengklaim bahwa “masalah utamanya adalah sintaks yang terlalu bertele-tele”
      Mereka memutuskan untuk tidak lagi mencoba mengubah sintaks penanganan error dalam masa depan yang dapat diperkirakan, dan berkat itu ada perhatian untuk melihat masalah lain, baik soal error maupun topik lain
    • Perlu diingat bahwa Go juga butuh waktu sangat lama sampai mendukung suatu bentuk generics
      Evolusi Go bergerak selambat gletser, dan bagi banyak orang itu bukan bug, melainkan fitur
    • Setuju 100%. Keduanya Googler, dan saya sangat kecewa lagi pada tim Go
    • Saya setuju dengan poin pertama, tetapi ini bisa sedikit dimitigasi dengan alat pengembangan seperti errcheck: https://github.com/kisielk/errcheck?tab=readme-ov-file
  • Penjelasan seperti “masukan survei bahwa error tidak punya stack trace bisa diselesaikan dengan membuat fungsi pembantu menghasilkan dan mengembalikan error yang diperkaya” terdengar konyol
    Lucu bahwa menyediakan stack trace secara manual seperti if err != nil { return fmt.Errorf("invalid integer: %q", a) } disebut “penanganan error”
    Kalau menurut definisi tim Go, exception berarti menangani error secara otomatis. Tentu saja di bahasa selain C++

    • Lucu melihat orang memandang stack trace yang memenuhi layar lalu menyebutnya jelas dan berguna
      Bisa saja begitu, tapi apakah semua itu benar-benar diperlukan? Bagaimana dengan biaya log?
      Menurut saya, error terbungkus satu baris yang memangkas noise dari framework dan runtime jauh lebih baik
      Jika dibungkus dengan baik, itu juga sangat mudah dicari, dan biasanya bisa dilacak lebih efektif daripada stack trace
      Selama memakai Go penuh waktu lebih dari 10 tahun, saya tidak pernah sekalipun membutuhkan kebisingan panjang-lebar dari fungsi runtime atau call stack
  • Dari sudut pandang developer Elixir, ini terlihat gila
    Di Erlang/Elixir, ini biasanya diselesaikan dengan fungsi mengembalikan tuple {:ok, result} atau {:error, description_or_struct}
    Dengan statement with milik Elixir, penanganan error bisa dikumpulkan di bagian bawah sehingga jauh lebih mudah dibaca
    Go juga tinggal menambahkan padanan klausa with, melanjutkan fungsi-fungsi selama error bernilai nil, lalu menaruh klausa penanganan error di bawah

    • Berdasarkan bukti yang tersedia, tampaknya sama sekali tidak ada kemungkinan Go mengadopsi statement with
      Menarik bahwa Go menunda sangat lama struktur-struktur dasar yang jelas bernilai seperti generics, penanganan error, dan manajemen paket karena kurangnya konsensus komunitas
      Generics butuh 13 tahun setelah dirilis sebagai open source, 16 tahun kemudian penanganan error masih belum ada, dan manajemen paket memakan waktu sekitar 9 tahun
      Pertimbangan matang memang bernilai, tetapi rilis juga bernilai. Orang-orang yang menulis 900 komentar GitHub pada akhirnya tetap akan memakai Go, dan kemungkinan memasukkan sesuatu ke bahasa lebih baik daripada terus menundanya
    • Multiple return Go itu sendiri, dari sudut pandang saya, terasa aneh
      Fungsi dengan beberapa tipe return tidak bisa melakukan apa-apa selain ditugaskan ke variabel
    • Pengguna Haskell dan penggemar Rust menganggap sum type sebagai milik mereka, lalu orang membaca dan memercayai komentar serta tulisan mereka dan jadi enggan pada sum type karena tidak ingin terseret ke lubang kelinci Hindley-Milner yang menakutkan
      Namun di Erlang dan Elixir, itu sepenuhnya idiomatis tanpa beban apa pun
      Bahkan sebenarnya jauh lebih kuat daripada keluarga ML, karena sum type di sana bersifat terbuka
  • Saya tidak mengikuti diskusi ini secara mendetail, tetapi saya tidak mengerti kenapa mereka tidak langsung mengadopsi cara ala Rust saja
    Setelah Go punya generics, cara itulah yang langsung saya tambahkan
    Dalam tulisan yang ditautkan, yang terlihat hanya penjelasan bahwa “di Rust tidak ada padanan untuk handle, dan kemudahan operator ? berpotensi membuat orang melewatkan penanganan yang semestinya”
    Namun saya tidak paham kenapa sesuatu yang praktis berarti mengabaikan error
    Separuh masalah dari cara Go adalah ia tidak memaksa apa pun terhadap hasil, dan hanya memaksa pemeriksaan error secara minimal
    x, err := strconv.Atoi("123"); fmt.Println("result:", x) akan menghasilkan declared and not used: err, tetapi setelah konversi kedua, meski err tidak diperiksa, karena nilai default y adalah 0, program bisa berjalan baik-baik saja tanpa menyadari ada masalah
    Bahkan jika dibiarkan kosong seperti if err != nil { }, itu tetap dikompilasi dan dijalankan, dan kita tidak bisa tahu bahwa ada sesuatu yang salah
    Jika nilai balik dibuat sebagai Result, maka dipaksa untuk mengambil keputusan. Kalaupun ada orang yang sembarangan memakai ! atau dengan mudah meneruskannya ke atas dengan ? tanpa menangani kasus error, apakah berarti panic juga akan dilarang?

    • Go tidak punya sum type, jadi tidak bisa memiliki Result
      Dan karena obsesi aneh bahwa semua tipe harus punya zero value yang ditentukan, sum type pun tidak bisa ditambahkan
    • Saya memahaminya sebagai: kalau ? nyaman dipakai, tidak akan ada lagi yang membungkus error
      Ini logika yang sangat meragukan
      Dari awal, ? bisa saja dirancang agar mendorong pembungkusan error
    • Alasannya karena ketika memasukkan gaya Rust ke Go, tidak jelas bentuk yang benar-benar setara itu seperti apa
      Misalnya, padanan From di Rust seharusnya seperti apa di Go?
    • ? visibilitasnya rendah, dan menyembunyikan percabangan alur kontrol di dalam satu statement atau expression
      Itu juga salah satu alasan Go menghilangkan operator ternary dan memilih statement if yang tiap cabangnya berada di baris terpisah
      Memasang breakpoint juga tidak mudah, dan ini membuat orang cenderung meneruskan error apa adanya ke atas alih-alih memperkaya atau menanganinya
    • Saya kira := adalah deklarasi sekaligus assignment dalam satu statement, tetapi di baris ke-5 contoh itu, bukankah err dideklarasikan ulang dan err baru menutupi err lama?
      Kalau begitu, karena variabel err baru tidak digunakan, seharusnya gagal dengan declared and not used: err
      Atau kalau variabelnya sudah ada, apakah := hanya bertindak seperti assignment biasa?
  • Pernyataan bahwa “tidak adanya stack trace pada error bisa diselesaikan dengan membuat helper function menghasilkan dan mengembalikan error yang sudah diperkaya” terlalu optimistis terhadap kenyataan
    Bahasa yang memiliki stack trace memberikannya secara gratis, tetapi di Go kita harus mengimplementasikannya setiap kali
    Anda sendiri mungkin developer yang disiplin dan selalu menambahkan detail, tetapi tidak semua anggota tim punya disiplin yang sama
    Hal terbaik dari stack trace adalah ia memberi jalur pemanggilan sampai ke error
    Jika error terjadi di method yang dipanggil dari banyak tempat, dengan stack trace kita bisa langsung tahu jalur mana yang ditempuh
    Selama bertahun-tahun melakukan pekerjaan mirip sysadmin/SRE dan menyelesaikan banyak masalah, masalah yang mudah saat ada stack trace biasanya penyebabnya jelas dan selesai dalam 1–2 menit
    Di Go, jika seseorang tidak memperkaya error atau menggunakan ulang pesan error yang sama, masalah yang mudah pun berubah menjadi pekerjaan deduksi dan memakan waktu lebih lama