Go: proposal: biarkan "jika err != nil" sendirian?

Dibuat pada 28 Jun 2019  ·  314Komentar  ·  Sumber: golang/go

Proposal Go2 #32437 menambahkan sintaks baru ke bahasa untuk membuat boilerplate if err != nil { return ... } tidak terlalu rumit.

Ada berbagai proposal alternatif: #32804 dan #32811 karena yang asli tidak disukai secara universal.

Untuk memasukkan alternatif lain ke dalam campuran: Mengapa tidak menyimpannya apa adanya ?

Saya mulai menyukai sifat eksplisit dari konstruksi if err != nil dan karena itu saya tidak mengerti mengapa kita membutuhkan sintaks baru untuk ini. Apakah itu benar-benar buruk?

FrozenDueToAge Proposal Proposal-Hold error-handling

Komentar yang paling membantu

seharusnya hanya ada satu cara untuk melakukan sesuatu

Semua 314 komentar

Saya kedua ini. Saya sangat suka bagaimana mendekorasi setiap kesalahan sebelum mengembalikannya menambahkan dokumentasi yang dapat dibaca manusia ke sumbernya (biasanya kami memformat kesalahan kami sebagai "tidak dapat [apa yang saya lakukan dalam baris kode ini]: [kesalahan sebelumnya]") dan juga kepada pengguna kesalahan membaca.

Kesalahan yang dihasilkan dengan cara ini sangat informatif dan lebih mudah dibaca daripada jejak tumpukan. Kesalahan tercetak yang menyertakan jejak tumpukan biasanya menganggap Anda memiliki akses siap ke sumber (administrator mungkin tidak memiliki akses seperti itu) dan benar-benar mengetahui cara Anda dalam kode.

Kesalahan tanpa konteks atau penelusuran apa pun (string kosong "EOF") sama sekali tidak berguna. Saya pikir memiliki pintasan yang memudahkan untuk mengembalikan kesalahan telanjang akan membuat program Go mencetak banyak kesalahan yang tidak berguna.

Jika ada, kita harus mendorong dan mendukung kesalahan dekorasi dengan konteks, mungkin dengan aturan dokter hewan dan serat baru.

Saya juga menyukai pemeriksaan kesalahan secara eksplisit. try membingungkan dan pengembalian implisitnya aneh.

Saya pikir alih-alih memikirkan kembali kesalahan, kita dapat mencoba pendekatan alternatif untuk mempersingkat pemeriksaan ini.

Berikut adalah contoh yang saya tidak selalu setuju:

value, err := foo()
return err if err != nil

Ini akan memungkinkan pendekatan yang lebih pendek namun tetap eksplisit. Dan itu akan memungkinkan menambahkan konteks!

Yang mengatakan, inline ifs adalah hal Ruby dan tidak terasa sangat Goish, tapi ini hanya brainstorming. Mungkin kita menemukan sesuatu yang lain.


EDIT: Saya menambahkan proposal untuk ini di sini: https://github.com/golang/go/issues/32860

seharusnya hanya ada satu cara untuk melakukan sesuatu

[...]Mengapa tidak tetap seperti apa adanya?

Saya pikir adil untuk mengatakan bahwa kita semua tahu jawabannya. Anda hanya perlu membaca salah satu dari berbagai proposal untuk mengetahui jawabannya jika Anda benar-benar tidak tahu.

IMO, ada terlalu sedikit detail di sini bagi kita untuk melakukan diskusi terfokus (yaitu saya tidak berpikir itu memenuhi syarat sebagai proposal) dan itu akan segera berubah menjadi gudang sepeda lain yang penuh dengan sentakan lingkaran dan ide-ide yang membuat kode kurang mudah dibaca .

Begitu banyak ini.

Bisa dibilang saya masuk ke Go karena penanganan kesalahan eksplisit ini. Itu berada di antara try-catch implisit yang digunakan banyak bahasa dan tipe fungsi seperti Option atau Maybe, yang lebih suka dikembalikan ke pengguna dan ditangani secara eksplisit.

Saya tidak yakin apakah konstruksi baru akan benar-benar menyelesaikan ini. Jika Anda membungkus if err := nil dalam fungsi pembantu seperti ini, ini mungkin sedikit membantu (maafkan Go saya yang berkarat):

func handleErr(err error, cb func(error)) {
        if err := nil {
                cb(err)
        }
}

Tetapi masalah yang membuat fungsi pembantu ini kurang berguna secara umum adalah sistem tipe, yang merupakan topik yang berbeda.

Saya kedua ini. if err != nil { return err } bukan bagian dari kode apa pun di basis kode kami. Oleh karena itu mencoba "makro" tidak masuk akal sama sekali. Kami hanya mengembalikan kesalahan yang dibungkus, dengan pesan yang menjelaskan konteksnya.

Menambahkan konteks melalui penangguhan juga tidak masuk akal, karena kami ingin mengembalikan pesan kesalahan yang berbeda untuk membedakan jenis kesalahan yang berbeda. try(fn(), "my error message: %w") mungkin berguna. Tetapi meskipun demikian, konstruksi if err != nil mungkin masih lebih disukai, karena panjang garis yang lebih pendek.

Terus terang, saya tidak ingin pengembalian implisit yang diberikan try . Jika kami memiliki obat generik, saya lebih suka solusi yang menggunakan perilaku monad-ish sebagai gantinya.

type Result<T> interface {
  Expect(err error) T
  OrElse(defaultValue T) T
}

func From<T>(value T, err error) Result<T> { ... }

Bagi saya, ini jauh lebih bersih daripada builtin yang saat ini diusulkan, meskipun perubahan lebih lanjut akan diperlukan di atas karena Anda akan memiliki proliferasi metode yang mengembalikan (nilai, kesalahan) dan Hasil

Proposal try , tidak memiliki cara untuk secara eksplisit menghiasi kesalahan, tidak memenuhi kebutuhan saya. Saya tidak bisa membayangkan pernah menggunakannya. Terus terang, itu mungkin juga disebut code_smell .

Mungkin tidak masuk akal untuk mengubahnya, karena masalah yang salah sedang mencoba untuk dipecahkan.

Kode yang kita kenal bukanlah penanganan kesalahan.

if err != nil {
  return err
}

Ini adalah kesalahan penanganan nil . Tidak ada titik dalam pola ini adalah nilai kesalahan yang ditangani.

Jika saya mendemonstrasikan ini dalam bahasa yang berbeda, Ruby.

begin
 some_method_that_raises_an_error
rescue => e # catch any exception
  retry e        # throw it up again
end

Ini menyampaikan perilaku yang sama dengan kode golang. Ketika kami mendeteksi bahwa pengecualian terjadi dan kemudian menaikkannya kembali. Kami hanya membuangnya ke tumpukan.

Di golang, kita return itu.

Di mana _penanganan kesalahan_ yang sebenarnya terjadi?

Kita semua memiliki pengalaman serupa tentang kegagalan pola ini. Misalnya, menerima kesalahan file not found dan kemudian menghabiskan banyak waktu untuk melacak _thrower_ asli dari kesalahan ini.

Inilah mengapa saya yakin proposal try (dan lainnya) salah. Kami tidak memiliki pola yang baik untuk benar-benar menangani kesalahan.

Saya telah melihat pemeriksaan string err.Error() , ketik pernyataan, dll. untuk benar-benar memeriksa kesalahan.
Kita membutuhkan pola untuk ketidakkonsistenan ini. Rasanya xerrs mungkin menyelesaikan ini, tetapi juga belum terasa lengkap.

Saya mendukung menjaga err!=nil check apa adanya.

Setiap kali saya menggali basis kode Go yang cukup besar, saya bertanya pada diri sendiri bagaimana saya bisa mengurangi beberapa boilerplate. Saya selalu kembali ke:

  • Codepath itu ada dengan satu atau lain cara.
  • Bahkan jika Anda tidak diharuskan untuk menyembunyikan codepath, memberi orang kesempatan untuk menyembunyikannya akan menjadikannya perilaku default (karena tampaknya kami masih mengukur seberapa sulit suatu bahasa digunakan berdasarkan jumlah baris).
  • Jika perilaku default menyembunyikan codepath maka saya akan mencari bug "pembersihan yang hilang" baru.
  • Arti dan pola untuk kesalahan yang dikembalikan cukup beragam sehingga proposal ini hanya akan menangkap sebagian dari masalah yang dirasakan
  • Jika hanya sebagian yang ditangkap maka kami pasti akan mendapatkan banyak solusi
  • Dengan banyak solusi akan muncul godaan untuk memiliki sihir adaptif kasus penggunaan untuk menggulungnya
  • Bahwa jika ini benar-benar sebuah masalah maka orang bebas untuk membuat solusi sederhana mereka sendiri atau menggunakan beberapa pola yang diadopsi secara massal. Saya belum melihat yang seperti itu. Mungkin aku hanya tidak melihat cukup keras.

Pelacak masalah berguna untuk banyak hal, tetapi satu hal yang tidak berguna adalah diskusi mendetail tentang topik yang kompleks. Pelacak masalah tidak menyediakan threading, dan membalas pesan tertentu itu canggung. Karena tidak ada proposal sebenarnya di sini, hanya tanggapan terhadap proposal lain, saya sangat mendorong Anda untuk membawa diskusi ini ke milis golang-nuts.

Jika saya boleh, saya percaya ini adalah jawabannya. Proposal kesalahan baru ini bertentangan langsung dengan tujuan bahasa.

Alasan saya menyukai golang adalah karena kesederhanaannya dan penggunaan control flow yang jelas. Salah satu hal yang paling saya benci tentang Java adalah konstruksi try throw. Ini sangat menjijikkan. Ini mendorong penanganan kesalahan yang mengerikan. Mengirim pengecualian ke tumpukan panggilan adalah metode penanganan aliran kontrol yang mengerikan dan menjijikkan. Di atas, itu mendorong untuk membungkus semuanya dalam cek raksasa dan menyebutnya sehari alih-alih mendokumentasikan diri sendiri dan menangani secara eksplisit setiap situasi kesalahan.

If err != nil mendorong penanganan kesalahan yang baik, mendokumentasikan diri sendiri dan mendorong dokumentasi yang baik untuk kasus tertentu, dan jujur ​​itu salah satu hal yang paling saya sukai tentang go. Membuat aliran kontrol baru ini menyela, menggunakan pengembalian dan parameter yang berantakan, agak ambigu, dan semantik yang membingungkan tidak sesuai dengan semangat bahasa yang saya kagumi.

Verbositas bukanlah hal yang buruk. Verbositas yang tidak perlu, tetapi saya berpendapat bahwa penanganan kesalahan go tidak perlu. Itu bagian dari pesona bahasa.

Sangat setuju. Penanganan kesalahan eksplisit adalah salah satu fitur terbaik dari bahasa IMO. Saya selalu merasa banyak orang yang terganggu olehnya hanya belum terbiasa.

Ini tidak baik untuk masalah dipisahkan, tetapi saya berpikir bahwa dua pendapat digabungkan menjadi satu pendapat dalam kasus ini.

  1. Kami tidak menyukai sintaks baru (coba atau sintaks if-err baru)
  2. Bagaimanapun, kami tidak ingin menambahkan sintaks baru

Ikon suara GitHub tidak dapat menafsirkan yang kedua.

Penanganan kesalahan eksplisit di go adalah salah satu alasan mengapa saya menyukai golang. Saya tidak mengerti mengapa pengembang go mana pun menginginkannya dengan cara lain. Saya pikir proposal untuk menambahkan sintaks baru sebagian besar dari orang-orang yang nyaman menggunakan sintaks yang digunakan dalam bahasa lain. mungkin perlu beberapa waktu untuk membiasakan diri tetapi itu bekerja dengan sempurna setelah Anda terbiasa.

Saya menulis #32811 dan saya lebih mendukung proposal ini... Saya lebih suka membiarkan penanganan kesalahan saja. Saya pikir reaksi emoji terhadap proposal ini mengatakan banyak hal.

Saya pribadi setuju dengan membiarkan penanganan err apa adanya. Salah satu hal yang saya suka tentang Go adalah bahasanya minimal, dan secara umum memiliki satu cara dalam melakukan sesuatu. Dengan menambahkan sintaks baru untuk penanganan kesalahan, kami akan membuat dunia di mana x% kode menggunakan metode saat ini, dan y% menggunakan metode baru. Ini akan, di antara masalah lain yang telah dibahas, membuat basis kode yang tidak konsisten. Saya pribadi tidak berpikir nilai sintaks penanganan kesalahan baru sepadan dengan pertukarannya, karena saya menganggap sintaks yang ada cukup/cukup.

Sebagai seseorang yang baru mengenal Golang, salah satu hal yang menurut saya menyegarkan tentang bahasa ini adalah penanganan kesalahan yang eksplisit. Saya telah bekerja di Java, Ruby, Python, dan Node cukup berat, dan menangani kesalahan jauh lebih berat daripada di Go. Saya lebih suka melihat 'jalur' kesalahan yang jelas, daripada menyiratkannya kepada saya oleh beberapa konstruksi bahasa yang membuatnya lebih kabur.

return ... if ...ˋ saran dari @andreynering sebenarnya cukup cerdas. Menjaga kode tetap eksplisit (tidak ada pemutusan aliran kontrol tersembunyi) saat memotong boilerplate (one-liner).

Setuju, biarkan if err != nil saja.

Saya lebih suka format saat ini. Polanya jelas dan mudah diajarkan. Membawa insinyur baru ke kecepatan itu sederhana karena mereka dapat mempelajari satu pola sederhana dan mengulanginya. Itu juga meminta pengguna untuk setidaknya mempertimbangkan kesalahan dalam konteks saat ini, memastikan bahwa setidaknya insinyur mengakui kesalahan dapat terjadi di sini dan saya perlu memikirkan apa yang harus dilakukan.

Saya menulis #32804 dan saya lebih suka melihat hal-hal TIDAK berubah. Jika kode Anda panjang, itu karena ia melakukan banyak hal. Jika Anda memiliki banyak kode penanganan kesalahan, itu karena Anda melakukan pekerjaan dengan baik dalam menangani semua kasus Anda.

Tolong, jangan menambahkan sesuatu hanya untuk menambah sesuatu.

Saya menikmati kesederhanaan penanganan kesalahan apa adanya.

Harapkan hanyalah anagram untuk kecuali, dan saya lebih suka tidak menggunakannya. Terima kasih telah memulai ini.

Tolong jangan ubah cawan suci saya.

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

@icholy Tentu, tetapi proposal saat ini meninggalkan banyak hal yang diinginkan. Mereka semua tampaknya mengaburkan penanganan kesalahan, kembali ke lebih banyak implementasi gaya coba/tangkap/akhirnya, gelembung penanganan kesalahan di luar konteks, atau membuatnya lebih rumit. Karena Go seharusnya menjadi bahasa yang sederhana, saya pikir banyak dari kita berharap untuk opsi yang sederhana. Saya belum melihat yang saya suka secara pribadi, jadi saya pikir pilihan yang lebih baik adalah mempertahankan pola saat ini.

Satu keluhan adalah harus mengetiknya, tetapi hampir setiap editor memiliki pintasan untuk menyisipkan cuplikan kode, jadi itu bukan masalah besar. Mungkin pengalaman saya sendiri telah menggunakan Go sejak pra 1.0, tetapi kebetulan saya menyukai kesederhanaan dan tidak keberatan dengan redundansi.

@kevineaton Anda pikir try rumit?

Saya setuju dengan ini sepenuhnya. Saya bahkan secara pribadi tidak yakin kita perlu melakukan apa pun - Saya setuju cek if err != nil terlihat canggung pada blush pertama tetapi saya belum melihat apa pun yang diusulkan yang benar-benar menyelesaikan masalah tanpa secara luas melanggar hal-hal yang sebenarnya terjadi populer untuk.

@icholy setelah menghabiskan sepuluh tahun menulis Java dan Python sebelum Go, saya pikir itu bisa. Saya pikir Anda mengalami penangkapan pengecualian Pokemon, atau menangkap rantai beberapa pengecualian, dan sebaliknya memperkenalkan lebih banyak overhead dan boilerplate. Saya tidak akan kembali ke gaya penanganan kesalahan itu jika saya bisa menghindarinya, karena hampir selalu menyebabkan sakit kepala dan kebingungan TERUTAMA ketika mengajar. Saya juga mengajar ilmu komputer di atas pekerjaan sehari-hari saya sebagai arsitek perangkat lunak, jadi saya bias mengajar pengembang dan pendampingan baru. Saya akan memilih Go dan itu adalah penanganan kesalahan yang sederhana daripada penanganan kesalahan yang lebih rumit atau bernuansa setiap hari.

Pelacak masalah berguna untuk banyak hal, tetapi satu hal yang tidak berguna adalah diskusi mendetail tentang topik yang kompleks.

Bukankah _itu_ kebenaran. Tapi di sini kita.

if err != nil tidak akan hilang jika try ditambahkan. Saya percaya bahwa try akan menambah kejelasan pada jalur kode yang merupakan penerusan kesalahan yang berat atau di mana banyak kesalahan yang berbeda dapat disimpulkan dengan mudah dalam satu penangan kesalahan penangguhan. . Saya tidak benar-benar melihat bagaimana try mendorong untuk tidak menangani kesalahan lebih dari sekumpulan if-err-return-err kosong. Sangat mudah untuk mengabaikan penanganan kesalahan yang sebenarnya terlepas dari try ada atau tidak. Saya pikir try adalah salah satu saran terbaik untuk penanganan kesalahan karena sepertinya akan mudah untuk membaca kode yang menggunakannya..

Dua sen saya yang tidak diminta, rasanya tidak seperti "Pergi". Ini terlalu ajaib dan kita akan menggunakan konstruksi implisit daripada konstruksi eksplisit.

Dari FAQ Pergi

Mengapa Go tidak memiliki ?: operator?
_Tidak ada operasi pengujian ternary di Go. Anda dapat menggunakan yang berikut ini untuk mencapai hasil yang sama:_

if expr {
   n = trueVal
} else {
    n = falseVal
}

Alasan ?: absen dari Go adalah karena perancang bahasa telah melihat operasi yang digunakan terlalu sering untuk membuat ekspresi kompleks yang tidak dapat ditembus. Bentuk if-else, meskipun lebih panjang, tidak diragukan lagi lebih jelas. Sebuah bahasa hanya membutuhkan

@ianlancetaylor

Pelacak masalah berguna untuk banyak hal, tetapi satu hal yang tidak berguna adalah diskusi mendetail tentang topik yang kompleks. Pelacak masalah tidak menyediakan threading, dan membalas pesan tertentu itu canggung. Karena tidak ada proposal sebenarnya di sini, hanya tanggapan terhadap proposal lain, saya sangat mendorong Anda untuk membawa diskusi ini ke milis golang-nuts.

Anda dapat membalas pesan tertentu. Saya baru saja membalas pesan Anda. :)

Karena tidak ada proposal aktual di sini, hanya tanggapan terhadap proposal lain,

Sebuah proposal bagi saya berarti panggilan untuk perubahan. Isu khusus ini adalah anti-perubahan. Apakah Anda mengusulkan agar kami membuat proposal untuk _tidak_ mengubah penanganan kesalahan? Saya pikir sistem proposalnya bagus tetapi membuat status quo kurang terwakili.

setelah menghabiskan sepuluh tahun menulis Java dan Python ... Saya juga mengajar ilmu komputer di atas pekerjaan sehari-hari saya sebagai arsitek perangkat lunak

@kevineaton apakah kamu sudah selesai mengisap

Masalah ini berfungsi sebagai jajak pendapat yang berlangsung lama di tempat semi-resmi di mana pada dasarnya siapa pun dapat dengan mudah memilih atau menentang proposal.

Tidak mengubah bahasa untuk menghapus if err != nil adalah proposal cromulent sempurna yang pada dasarnya tidak memerlukan detail tambahan. Saya tidak yakin apa masalahnya. Tidak, itu tidak terlalu panjang dan sulit untuk grok. Itu tidak membuatnya salah atau buruk atau tidak cukup.

+1, jika tidak ada yang lebih baik, hal yang baik akan menjadi info stacktrace yang sangat bagus (tanpa bingkai dansa), saya kira x/errors sudah mencapai ini, tetapi, saya akan menyukai sesuatu ala Swift dalam waktu dekat, seperti menandai func s menggunakan throws kata kunci yang akan mengembalikan error + try kata kunci, mencegah kesalahan var shadowing (yang saya pribadi benci), seperti ini:

func a() (int) throws {
  throw &someError{}
}

anInt, err := try a()

@icholy Itu sangat tidak beralasan. Ini adalah tempat untuk diskusi dan komunitas Go seharusnya menjadi komunitas yang ramah. Tidak ada tempat untuk komentar seperti itu. Saya percaya Socrates memiliki sesuatu untuk dikatakan tentang penghinaan dalam sebuah debat.

Penanganan kesalahan saat ini rawan kesalahan manusia. Cukup mudah untuk lupa memeriksa err saat ini. Jika sudah ada pemeriksaan dalam ruang lingkup (dan sebagian besar waktu ada), kompiler tidak akan diakhiri dengan unused variable . Penanganan kesalahan harus ketat - Anda bisa _ kesalahan atau memeriksanya - tidak boleh ada pemotretan kaki.

@kevineaton Anda pikir try rumit?

try adalah bau kode. Ini memaksa lekukan di antara seluruh blok kode Anda, bukan hanya di satu tempat. Lebih jauh, sifat "gelembung" dari penanganan pengecualian menciptakan perilaku nondeterministik de facto dalam kode dan beberapa titik keluar.

Keindahan menggunakan beberapa nilai pengembalian alih-alih try adalah ada satu nilai untuk diperiksa ketika fungsi Anda selesai dan satu titik keluar dari fungsi Anda (kecuali, tentu saja, menggunakan pernyataan penjaga atau pengembalian eksplisit lainnya).

Blok try mengalahkan seluruh tujuan dari pengembalian berganda.

@fillest Meskipun itu akan membuat kode sedikit kurang terbaca, saya pikir ini akan menjadi nilai tambah dalam hal keamanan/penanganan kesalahan eksplisit. Jika Anda melihat kembali tujuan awal bagaimana kami menangani kesalahan di Go, saya pikir itu akan menjadi iterasi yang bagus untuk menghindari kelas bug yang Anda kutip sambil tetap mengejar semangat eksplisit menjadi baik.

Penanganan kesalahan saat ini rawan kesalahan manusia. Cukup mudah untuk lupa memeriksa err saat ini. Jika sudah ada pemeriksaan dalam ruang lingkup (dan sebagian besar waktu ada), kompiler tidak akan berhenti dengan variabel yang tidak digunakan. Penanganan kesalahan harus ketat - Anda _ kesalahan atau memeriksanya - tidak boleh ada pemotretan kaki.

@fillest Perubahan yang diusulkan untuk penanganan kesalahan membuat "pemotretan kaki" lebih mudah dan kesalahan lebih jelas karena dapat ditangani dengan malas.

Saya berhenti menggunakan Go karena kurangnya obat generik, kecenderungan boilerplate, GC, kurangnya batasan sumber daya/akuntansi dan beban kerja yang dihasilkan dari PHP noobs yang tidak mengerti apa yang dilakukan oleh kompiler. Haskell, C#, dan lainnya menyelesaikan penanganan kesalahan dengan cukup baik... proposal Go 2 terlihat baik-baik saja jika memiliki penanganan kasus yang eksplisit seperti sebelumnya (tidak yakin).

Penanganan kesalahan adalah inti dari pemrograman. Memodelkan logika bisnis (betapapun rumitnya) selalu lebih sederhana daripada menanggapi kondisi tidak valid yang dihasilkan logika ini. Hanya meneruskan kesalahan adalah bau kode. Saya berharap Go tidak mendorong perilaku ini tetapi mempromosikan pola manajemen kesalahan. Pemula sering bingung dengan semua kode penanganan kesalahan ini karena mereka belum menyadari betapa pentingnya manajemen kesalahan.

Sepenuhnya setuju, karena try builtin tidak akan membantu untuk membungkus kesalahan dan menambahkan informasi ke dalamnya meskipun sedikit.

Sebelum menulis ulang dengan try :

_, err := doSomething()
if err != nil {
    return nil, errors.Wrap(err, "failed to do something")
}

_, err = doOtherThing()
if err != nil {
  return nil, errors.Wrap("failed to do the other thing")
}

Bayangkan apa yang akan terjadi setelah menulis ulang dengan try .

Karena try sudah bertindak seperti fungsi 1-argumen dengan menyertakan argumennya dalam tanda kurung, ia dapat menerima argumen ke-2 yang merupakan kode pembungkus kesalahan.

try(extract_value(try(get_data(1), errors.Wrap(err, "failed to get data")), errors.Wrap(err, "failed to get data")))

Di mana nilai err harus diperkenalkan secara implisit (dengan cara yang higienis). Kemudian jika try digunakan sebagai fungsi 1-argumen maka itu hanya akan mengembalikan kesalahannya tidak berubah.

Saya setuju, satu-satunya hal "gula sintaksis" yang mungkin membuat penanganan kesalahan sedikit lebih sederhana adalah membiarkan kita melakukan sesuatu seperti berikut ini ketika kita memiliki banyak pengembalian dari fungsi kita... garis bawah hanya akan menjadi nilai default dari apa pun jenis pengembaliannya

if err != nil {
    return _, _, err
}

@sorenvonsarvort sepertinya tidak terlalu buruk bagi saya:

var errContext string 

defer func() {
  // err is a named return
  if err != nil {
    err = fmt.Errorf("%v: %w", errContext, err)
  }
}()

errContext = "failed to do something"
_ := try(doSomething())

errContext = "failed to do other thing"
_ := try(doOtherThing())

Menurut pemahaman saya, Anda juga masih dapat menggunakan if err != nil { ... } jika lebih jelas untuk bagian kode tertentu.

try bersinar dalam kasus lain. Bayangkan sesuatu yang lebih seperti:

func trySomeComplexOp() (r result, err error) {
  a := try(step1())
  b := try(step2(a))
  c, d := try(step3(b))
  return try(lastStep(c, d)), nil
}

Kode seperti kode di atas bisa jauh lebih bersih daripada jika Anda harus menaburkan di blok if err != nil . Go adalah tentang "keterbacaan linier" jadi saya pikir try baik untuk tujuan itu.

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

Ini adalah minoritas vokal dan saya yakin sebagian besar dari mereka bahkan tidak menggunakan Go

@sirkon apa dasar pernyataan itu?

@sorenvonsarvort sepertinya tidak terlalu buruk bagi saya:

Kode seperti kode di atas bisa jauh lebih bersih daripada jika Anda harus menaburkan di blok if err != nil . Go adalah tentang "keterbacaan linier" jadi saya pikir try baik untuk tujuan itu.

Di Rusia kami menyebutnya «экономия а ах». Gunakan google translate untuk mendapatkan makna.

Bagi mereka di utas ini yang belum melakukannya, saya akan merekomendasikan membaca komentar ini tentang masalah proposal try . Ini membahas praktik terbaik konteks kesalahan umum dan bagaimana hal itu dapat diekspresikan dengan try .

Saya pikir mungkin konteks kesalahan telah menjadi sedikit dogmatis di komunitas Go. Saya tahu saya secara pribadi telah jatuh untuk ini dan terlalu mengontekstualisasikan kesalahan saya, menghasilkan pesan yang sangat panjang, berulang, dan sulit dibaca. Ada banyak nuansa mengenai kapan harus mengkontekstualisasikan kesalahan dan kapan tidak.

Saya suka bahwa try pada dasarnya adalah jalan pintas dan mengurangi beberapa kode boilerplate. Tapi kami kehilangan kemampuan untuk membungkus kesalahan dengan informasi tambahan. Namun, perubahan berikut mungkin memperbaikinya:

f := try(os.Open(filename))

menjadi

f := try(os.Open(filename), "open data file")

Tentu saja, jika Anda perlu melakukan lebih dari itu, cara "penuh" untuk melakukan cek err != nil masih tersedia.

Saya setuju dengan ini, tetapi saya akan menghormati permintaan dari tim go untuk memiliki lebih banyak pengalaman dengan perubahan sebelum memiliki pendapat akhir.

Tetapi pengalaman awal saya dengan perubahan itu tampaknya mendukung bahwa itu benar-benar tidak perlu. Saya memiliki 2 program "dunia nyata" dengan masing-masing sekitar 10 ribu baris dan menjalankan uji coba di kedua program tersebut menunjukkan bahwa tidak ada yang akan mendapat manfaat dari perubahan ini. Ini mudah dijelaskan oleh fakta bahwa keduanya selalu menambahkan konteks pada kesalahan. Saya memiliki program "mainan" lain yang lebih kecil di Go dan tryhard menemukan 1 kasus di mana saya bisa menggunakan try di salah satunya, tapi hanya itu.

Saya mengakui bahwa orang lain mungkin memperlakukan kesalahan secara berbeda dari saya dan saya mengakui kemungkinan bahwa try dapat digunakan dengan cara yang positif. Kode sumber tryhard itu sendiri memiliki beberapa kasus berturut-turut return err , yang jika digunakan try saya tidak berpikir keterbacaan akan dikompromikan sebanyak itu. Tapi saya hanya takut disalahgunakan, karena itu akan berdampak pada keterbacaan. Sebuah contoh yang baik disediakan di sini . Dan kemudian menentukan apa yang baik digunakan atau tidak akan menjadi cerita lain.

Juga, saya suka bagaimana orang biasanya hanya bisa membaca kode go meskipun mereka tidak memprogram go sendiri. Ini akan membuat mereka harus mempelajari keajaiban yang dilakukan try , khususnya karena ia melakukan hal yang berbeda dari try pernah mereka lihat dalam bahasa lain. Hal ini juga berlaku untuk orang baru yang datang ke bahasa tersebut, ini hanyalah fitur lain yang harus mereka pelajari dalam bahasa yang bangga menjadi sederhana dengan memiliki "fitur yang Anda butuhkan".

Kita lihat saja. Saya akan lebih banyak bereksperimen dengan perubahan ini, tetapi saya tidak yakin itu akan mengubah posisi saya.

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

@icholy Seperti yang saya katakan, saya suka menambahkan konteks ke kesalahan. Dalam hal itu, "Penanganan kesalahan yang lebih efisien" bagi saya berarti cara yang lebih baik untuk menyediakan konteks itu dan untuk mendapatkan informasi darinya. Misalnya, dengan semua konteks yang saya tambahkan ke kesalahan saya seharusnya sepele untuk menanyakan "konteks" apakah kesalahan itu disebabkan oleh batas waktu. Tapi tidak. Anda biasanya harus menggunakan pkg/error , membuat "struktur kesalahan" Anda sendiri dan/atau membuat metode untuk bekerja dengannya yang bergantung pada implementasinya dapat menggunakan pencarian string. Saya lebih suka melihat sesuatu yang akan menyelamatkan saya dari membuat seluruh struct dan metode daripada hal-hal yang menyelamatkan saya satu if sangat jarang sekali. Dan seperti yang dikatakan sebelumnya, dapatkah Anda benar-benar menyebutnya "penanganan kesalahan" ketika perubahan ini pada dasarnya menyediakan cara yang lebih nyaman untuk tidak benar-benar menangani kesalahan?

Anda pikir try rumit?

Secara terpisah try tidak rumit, tetapi perubahan bahasa tidak dipertimbangkan secara terpisah. Mempertimbangkan:

  • Peningkatan beban kognitif dari mempelajari semantik bawaan baru
  • Pengurangan keterbacaan karena penggunaan try karena lebih pendek, dalam kasus di mana if err != nil {return ... errors.Wrap() } seharusnya digunakan sebagai gantinya

Saya menggemakan sentimen di atas bahwa kesederhanaan (memiliki satu cara untuk memeriksa kesalahan) lebih penting daripada cara singkat untuk memeriksa kesalahan.

Bukankah cara menangani kesalahan adalah melalui pernyataan global itu dan jika ini adalah sesuatu yang harus diabaikan lalu Bagaimana situasi panik ditangani ?? Saya akan mendukung penanganan kesalahan yang lebih baik karena paradigma pemrograman lain menangani kesalahan hari ini tetapi tidak mengabaikan

Saya tidak melihat ada masalah dengan proposal try ?
Jika Anda ingin menggunakan perilaku lama atau membutuhkan cara lain untuk menangani kesalahan, mengapa tidak menggunakan kembali cara lama? Tidak ada yang menusukkan pisau ke penekan leher Anda menggunakan sintaks try ?
Sintaks try sederhana, dan cara yang bagus untuk mengurangi kode boilerplate, saya tidak tahu mengapa gopher menyukai cara sadisme?

Bagaimana jika gofmt diubah sedemikian rupa sehingga satu pernyataan jika blok tetap pada satu baris?

Dengan begitu, kita bisa saja membungkus kesalahan yang hanya membutuhkan satu baris untuk ditangani, bukan tiga untuk sebagian besar kasus. Ini akan mengurangi ruang vertikal yang diambil oleh penanganan kesalahan dan membuatnya tampak seperti penanganan kesalahan tidak menghabiskan lebih dari setengah ruang vertikal dalam fungsi rata-rata.

Berikut tampilannya:

// we already have an err in scope
err = frub.Confozzle(foo, bar, baz)
if err != nil { return errors.Wrap(err, "confozzling didn't work") }

Saya pikir mungkin konteks kesalahan telah menjadi sedikit dogmatis di komunitas Go. Saya tahu saya secara pribadi telah jatuh untuk ini dan terlalu mengontekstualisasikan kesalahan saya, menghasilkan pesan yang sangat panjang, berulang, dan sulit dibaca. Ada banyak nuansa mengenai kapan harus mengkontekstualisasikan kesalahan dan kapan tidak.

Pembungkusan kesalahan dan tumpukan bingkai/pencetakan kesalahan akan membuat lebih mudah. Saya pikir akan ada solusi yang baik untuk itu pada waktunya tetapi tidak sekarang.. Secara pribadi saya lebih suka menunggu dengan memperkenalkan fitur go2 yang lebih kuat hingga polimorfisme parametrik diselesaikan karena berpotensi berguna saat merancang fitur lainnya

Saya sangat setuju dengan membiarkannya apa adanya. Ini agak terlalu bertele-tele tetapi cukup mudah untuk diikuti.

Jika saya bisa mengurangi

if err := foo.x(a, b); err != nil {
    return err
}

if err := foo.y(); err != nil {
    return err
}

if err := foo.z(c); err != nil {
    return err
}

untuk sesuatu seperti

if err := check foo.x(a, b), foo.y(), foo.z(c); err != nil {
    return err
}

mungkin juga akan lebih bagus tanpa mengubah idiom terlalu banyak IMHO.

@henvic Saya pikir masalahnya adalah Anda berasumsi Anda ingin menangani tiga kesalahan dengan cara yang sama. Go memaksa Anda untuk memikirkan cara menangani setiap kesalahan satu per satu. Memiliki pemeriksaan kesalahan terpisah memperjelas hal ini. Menggabungkannya menjadi satu membuat dev harus secara kognitif kembali dan memeriksa, haruskah kesalahan ini _benar-benar_ diperlakukan dengan cara yang sama? Saya pikir dengan proposal ini kita kehilangan kejelasan dan memaksa memikirkan kesalahan untuk beberapa pukulan kunci yang lebih sedikit.

@sanbornm , Anda benar. Saya setuju.

check ini juga bisa menjadi operator checkNonZero yang hanya akan mengambil satu argumen pengembalian dan kembali pada nilai bukan nol pertama (seperti null). Tapi selain terlalu kabur, dan lebih mempengaruhi bahasa. Bahkan hanya sedikit memberikan petunjuk bahwa Anda tidak boleh menggunakannya jika mengharapkan, katakanlah, io.EOF. Kemungkinan lain, mungkin, mengandalkan go vet untuk setidaknya memberi tahu Anda tentang kasus yang paling umum (seperti io.EOF saat membaca dari pipa)... semua untuk saya.

Saya tidak melihat ada masalah dengan proposal try ?
Jika Anda ingin menggunakan perilaku lama atau membutuhkan cara lain untuk menangani kesalahan, mengapa tidak menggunakan kembali cara lama? Tidak ada yang menusukkan pisau ke penekan leher Anda menggunakan sintaks try ?
Sintaks try sederhana, dan cara yang bagus untuk mengurangi kode boilerplate, saya tidak tahu mengapa gopher menyukai cara sadisme?

Kita semua hidup dalam komunitas. Setiap hari saya bekerja dengan banyak kode yang ditulis oleh orang lain. Jadi perubahan bahasa akan mempengaruhi saya bahkan jika saya tidak menggunakannya.

Dalam proyek besar, log terburuk dihasilkan oleh fungsi yang kita lupa ditulis seseorang, yang memanggil perpustakaan yang memanggil perpustakaan yang memanggil perpustakaan yang melemparkan new Exception() generik yang tidak tertangkap sampai penangan pengecualian "Pokemon" melakukannya dan mencatat kesalahan umum. Yang terburuk kedua adalah sama, tetapi dengan jejak tumpukan beberapa ratus baris yang tidak dapat dipahami, yang saya kira kita akhirnya dapat mengetahui penyebabnya (untungnya hanya dengan mencari github.com/<us>/<ourproject> menemukan sebagian besar informasi yang relevan, tetapi kadang banyak). Terlepas dari namanya, "Pengecualian" sangat tidak biasa dalam proyek-proyek besar Java.

Sementara itu, bahkan ketika ada banyak konteks yang berlebihan, string kesalahan Go sederhana seperti "narf: Error unpoiting the zort: foo: Unexpected bar in baz: {\"ork\": \"morpork\"}" (dalam pengalaman saya) biasanya sangat mudah untuk ditafsirkan, selama kita rajin menyematkan konteks penting di suatu tempat di nilai kesalahan yang sebenarnya. Jika konteks penting ternyata hilang, itu _juga_ biasanya cukup jelas. "Perbaikan" dalam kasus-kasus itu menambahkan lebih banyak konteks dan menunggu kesalahan lain, jadi itu tidak sempurna, tetapi pada keseimbangan saya masih lebih suka ini untuk menggulir melalui jejak tumpukan dan/atau mengandalkan dependensi dari dependensi dependensi saya untuk "membuang " atau "naikkan" pesan kesalahan waras. Saya sangat menghargai bagaimana nama panic() tampaknya mencegah sebagian besar pengembang Go menyebarkan secara bebas apa yang pada dasarnya adalah fitur bahasa yang sama. Jangan sampai error dan panic menjadi hal yang sama.

Saya kadang-kadang mengalami situasi di mana suatu fungsi memiliki selusin mode kegagalan, dan sebagian besar dari mereka berhak mendapatkan pesan kesalahan yang sama. Pengulangan tidak terlalu mengganggu saya, tetapi biasanya ada orang lain di tim saya yang mengganggu, jadi kami berkompromi dengan mendeklarasikan penutupan di awal fungsi untuk menangani kesalahan umum tersebut.

func foo(a, b, c SomeArgType) (x, y, z SomeReturnType, err error) {
  handleError := func(handleErr error) (x, y, z SomeReturnType, err error) {
    log.WithFields(logrus.Fields{
      "package": "foo",
      "func": "foo",
      "arguments": map[string]SomeArgType{"a": a, "b": b, "c": c},
      "error": handleErr,
    }).Error("Error fooing the bar")
    return reasonable, default, values, handleErr
  }

  err := doABunchOfThings()
  if err != nil {
    return handleError(err)
  }
}

Yang memang _masih_ merupakan solusi yang tidak sempurna dalam beberapa hal. Tapi saya suka melakukan ini membuatnya sangat mudah bagi pengembang masa depan untuk tetap memahami kapan dan apa foo kembali, tanpa aliran kontrol melompat terlalu banyak.

Jika "masalah" pengulangan ini sangat umum di banyak paket alih-alih (seperti yang biasanya saya lihat) terbatas pada beberapa fungsi kompleks tak tereduksi dalam paket kompleks tak tereduksi, "functor" seluruh proyek mungkin dapat digunakan untuk akhir yang serupa, dan (menghela napas) jika konsep tipe parametrik akhirnya ditambahkan ke bahasa, Anda dapat menyembunyikan lebih banyak detail di balik pabrik penanganan kesalahan tanpa perlu bergantung pada coba/tangkap.

@thomasf

Pembungkusan kesalahan dan tumpukan bingkai/pencetakan kesalahan akan membuat lebih mudah

Saya setuju.

Secara pribadi saya lebih suka menunggu dengan memperkenalkan fitur go2 yang lebih kuat hingga polimorfisme parametrik diselesaikan karena berpotensi berguna saat mendesain fitur lainnya

Beberapa orang dalam proposal try mendiskusikan menunggu obat generik juga, tetapi tidak jelas bagi saya bagaimana polimorfisme parametrik akan membuat proposal try berbeda. Itu sudah built-in, jadi tidak terbatas pada batasan apa yang bisa kita ungkapkan dalam bahasa.

@icholy

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

Hanya untuk menanggapi ini; ada juga mayoritas di Inggris yang mendukung Brexit. Tentu, UE juga membawa beberapa kerugian yang ditanggapi oleh masyarakat umum. Namun, setelah semua alternatif diajukan, sepertinya tinggal di UE tidak akan terlalu buruk.

Sekarang sama sekali bukan niat saya untuk mempolitisasi ini, dan Anda mungkin tidak setuju dengan hal di atas. Tapi apa yang ingin saya tunjukkan adalah bahwa bahkan ketika mayoritas awalnya menganggap sesuatu sebagai gangguan, itu masih bisa menjadi solusi terbaik setelah semua alternatif telah diperiksa.

Saya tidak terlalu berpendapat tentang penanganan kesalahan, tetapi itu _bisa_ menjadi argumen untuk membiarkan hal-hal apa adanya.

Dalam lingkungan pengkodean profesional, kami memanfaatkan praktik penanganan kesalahan saat ini untuk memberi anotasi pada sistem penelusuran dan menghias log. Selain itu, pengembalian implisit agak seperti menggunakan kepanikan dalam fungsi perpustakaan yang diekspor, karena mengaburkan keterbacaan kontrol aliran langsung.

@icholy

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

Hanya untuk menanggapi ini; ada juga mayoritas di Inggris yang mendukung Brexit. Tentu, UE juga membawa beberapa kerugian yang ditanggapi oleh masyarakat umum. Namun, setelah semua alternatif diajukan, sepertinya tinggal di UE tidak akan terlalu buruk.

Anda tidak perlu mempertimbangkan klaim orang ini dengan serius: Jumlah emoji menunjukkan bahwa orang umumnya tidak menyukai proposal try dan mereka umumnya menyukai proposal "biarkan apa adanya".

PS dalam praktik saya, sebagian besar orang yang tidak menyukai Go di domain utamanya (layanan jaringan, utilitas CLI) bahkan belum menggunakannya. Jadi saya lebih suka mengabaikan pendapat mereka.

Kami membutuhkan opsi yang lebih baik, tidak terlalu kontroversial, daripada proposal try .
Saya tidak melihat urgensi untuk solusi tergesa-gesa.

@velovix Saya pikir saya lebih membenci polimorfisme parametrik daripada mencoba/menangkap kesalahan "penanganan", tetapi jika itu memang menjadi fitur bahasa, saya dapat melihat beberapa cara untuk menghindari kebutuhan akan fitur bahasa bawaan lainnya.

Untuk satu hal, ketika kode yang orang tidak ingin ulangi adalah boilerplate seperti:

foo, err := Foo()
if err != nil {
  log(err)
}
bar, err := Bar(foo)
if err != nil {
  log(err)
}
// ...

Kemudian beberapa kombinasi fungsi parametrik, inferensi tipe, dan pola desain objek gaya _maybe_ atau _optional_ akan secara langsung (heh) mengurangi boilerplate tanpa menggunakan strategi aliran kontrol non-linear yang aneh:

func<T> DoWithErrorLogging(f func(any...) (T, error), args... any) T {
  t, err := f(args...)
  if err != nil {
    log(err)
  }
  return t
}
// ...
foo := DoWithErrorLogging(Foo)
bar := DoWithErrorLogging(Bar, foo)

IMO ini semua akan jauh, jauh lebih buruk daripada Go1. Tetapi lebih baik daripada memiliki _plus_ coba/tangkap kata kunci ini dalam bahasa tersebut.

Sejujurnya... Seperti yang terjadi sekarang, saya pikir perubahan "melanggar" favorit saya untuk Go2 hanya akan memperbaiki semua ketidaknyamanan kecil di Go1, seperti net/http default menjadi global bersama yang dapat diubah bersarang di dalam global bersama yang dapat diubah (hanya membuat cleanhttp standar Hashicorp, pada dasarnya), atau (*time.Timer).Reset() memiliki nilai pengembalian yang tidak berguna yang hanya perlu Anda ketahui, atau seluruh paket syscall . Go3 dapat dirilis segera setelah itu dengan tumor apa pun yang ingin ditumbuhkan orang; Saya tidak mengerti mengapa perubahan kecil dan besar harus dilakukan dalam satu rilis.

Saya mendukung try ... bila digunakan dengan hemat. Saya menduga bahwa proyek-proyek populer akan menambahkan pedoman tentang kapan/jika mereka setuju dengan penggunaan try, dan proyek kecil/baru/satu orang kadang-kadang akan mengalami kesalahan yang buruk - dan dengan demikian kurang digunakan - karena try terlalu sering. Proyek-proyek itu akan mati atau diperbaiki atau bercabang.

Saya benar-benar tidak melihat penambahan try ke bahasa itu terlalu mengerikan. Jika ketakutan terburuk orang terbukti terbukti, penggunaannya akan disukai. Orang yang tidak berpengalaman akan menggunakannya tanpa pandang bulu, sementara yang lain tidak. Ini bukan akhir dunia.

Jika try ditambahkan, saya mungkin akan menggunakannya dalam beberapa kasus. Kasus-kasus itu adalah, di mana kesalahan dikembalikan tetapi saya pikir itu sangat tidak mungkin untuk benar-benar menjadi kesalahan sehingga saya tidak melihat gunanya menambahkan konteks, dan saya hanya mengembalikan kesalahan apa adanya. Misalnya, jika saya baru saja membuat sistem file yang mengisi disk yang saya tahu adalah 1 TB, saya bisa yakin ada ruang untuk membuat file atau direktori 1kb. Jika gagal, saya tidak ingin mengabaikan kesalahan - itu bisa menunjukkan bug di tempat lain, kegagalan perangkat keras, dll. Namun, itu tidak benar-benar layak dilakukan untuk membuat anotasi setiap kesalahan yang sangat tidak mungkin.

Saya tidak suka bagaimana try(..) hanya meletakkan satu pasang lagi tanda kurung/kurung pada tumpukan pikiran pembuat kode untuk dipikirkan saat mengetik. Dan untuk waktu yang paling lama yang bisa saya bayangkan!

Jadi ini lebih baik:
nilai, err := foo()
kembali err jika err != nil

Tapi tetap saja ini sangat umum. Jadi saya ingin jika smt seperti ini entah bagaimana mungkin:

nilai, periksa err := foo()

Jika Go ingin menjadi bahasa yang mudah dibaca, kemampuan berpikir yang sulit dibaca atau dipahami harus diminimalkan.

Jika Go ingin memiliki penanganan kesalahan yang baik, itu harus mendorong kesalahan untuk memiliki konteks tambahan saat mereka naik ke tumpukan panggilan. Persyaratan menggunakan penangguhan untuk menangani kesalahan tampaknya membingungkan. Bagaimana jika penangan kesalahan Anda memiliki kesalahan? Penangguhan dieksekusi dalam urutan tumpukan, apakah kita perlu mendeklarasikan penangan secara terbalik?

Jika pernyataan langsung, dan menyisakan sedikit ruang untuk ambiguitas di sini. Saya merasa try sedang memecahkan nit daripada masalah rekayasa nyata. Saya suka proposal ini karena memungkinkan mayoritas diam untuk akhirnya membuat pernyataan tanpa sepenuhnya memahami setiap aspek dari proposal yang rumit ini.

@icholy Harap sopan. Harap perhatikan Kode Etik Gopher: https://golang.org/conduct. Terima kasih.

Semua orang: selain komentar saya di atas (https://github.com/golang/go/issues/32825#issuecomment-506740412) harap perhatikan https://golang.org/wiki/NoPlusOne. Tidaklah membantu untuk membuat komentar yang mengatakan sedikit lebih dari "Saya setuju" atau "Saya tidak setuju." Gunakan tombol emoji sebagai gantinya. Terima kasih.

@sanbornm

(Saya setuju bahwa mungkin untuk membalas pesan; saya mengatakan itu canggung, bukan tidak mungkin. Dan poin saya tentang threading masih berlaku, karena mini-thread ini hilang dalam badai komentar lain.)

Sebuah proposal bagi saya berarti panggilan untuk perubahan. Isu khusus ini adalah anti-perubahan. Apakah Anda mengusulkan agar kami membuat proposal untuk tidak mengubah penanganan kesalahan? Saya pikir sistem proposalnya bagus tetapi membuat status quo kurang terwakili.

Tidak perlu membuat proposal A yang mengatakan bahwa proposal B tidak boleh diadopsi. Suarakan proposal B sebagai gantinya. Untuk pembahasan detail proposal B, gunakan proposal tersebut atau milis.

(Saya mengerti bahwa proposal B dalam kasus ini terkunci; fakta bahwa proposal ini memiliki 77 komentar dalam waktu kurang dari sehari menunjukkan alasannya. Tingkat diskusi ini bekerja lebih baik di milis daripada pelacak masalah.)

@ianlancetaylor

(Saya setuju bahwa mungkin untuk membalas pesan; saya mengatakan itu canggung, bukan tidak mungkin. Dan poin saya tentang threading masih berlaku, karena mini-thread ini hilang dalam badai komentar lain.)

Cukup adil, itu masuk akal. Milis sangat bagus tetapi saya pribadi merasa lebih mudah untuk berkontribusi melalui GitHub dalam hal ini. Saya tidak punya banyak hal untuk dikatakan selain penanganan kesalahan saat ini sangat bagus dan saya berharap itu tetap sama. Emoji/suara sangat bagus untuk ini. Anda mungkin tidak ingin 100 orang menulis "Tolong tinggalkan penanganan kesalahan sendiri" di milis di mana 100 "suara" sudah cukup.

Karena masalah ini dikunci, itu tidak dapat lagi "dipilih" dengan Emoji. Itulah sebabnya saya percaya masalah ini dibuat sejak awal.

Poin sampingan tetapi terkait, manajemen ketergantungan tidak ditangani dengan baik. Dep bekerja dengan baik dan go mod dipilih (dari apa yang tampak) entah dari mana [1]. Saya mengerti inilah mengapa sistem proposal dibuat. Saya hanya merasa sistem proposal dalam hal ini mungkin kurang mewakili komunitas jika masalah terkunci dan kami disuruh pergi ke milis.

[1] https://twitter.com/_rsc/status/1022588240501661696

Sunting: Tim dan komunitas Go sebagian besar melakukan pekerjaan luar biasa dengan mendengarkan umpan balik komunitas. Saya menghargai semua pekerjaan yang masuk ke dalamnya. Survei Go adalah contoh yang bagus.

@sanbornm

Dep bekerja dengan baik

Perlu tidak setuju di sini. Modul Go akhirnya memecahkan masalah "gobindata" yang tidak diketahui dengan caching persisten mereka dengan https://proxy.golang.org

Dep dude itu bahkan tidak menyadari masalahnya dan malah mempermainkan "memastikan" melalui VCS.

@sirkon Ini sedikit keluar dari topik tetapi Anda tidak memerlukan semua itu jika Anda vendor deps seperti yang dilakukan Dep.

Seperti berdiri, saya pikir saya lebih suka membiarkan hal-hal apa adanya kecuali lebih banyak batasan ditambahkan, seperti 1 pernyataan coba per baris. Alasan mempertimbangkan contoh ini dari proposal - tampaknya cukup tidak berbahaya info := try(try(os.Open(file)).Stat()) tetapi kebocoran menangani file di luar cakupan aliran kontrol normal. Saya pikir kita akan melihat peningkatan kebocoran sumber daya file dengan implementasi io.Closer atau fungsi pembersihan lain yang mungkin dihindari orang dalam mengejar kode yang lebih ringkas.

Mungkin beberapa orang akan menganggapnya tidak penting karena f tidak akan lagi ditayangkan dan dengan demikian memenuhi syarat untuk GC segera dan di beberapa titik finalizer akan memastikan bahwa f ditutup. Saya pikir itu mengubah konvensi sebelumnya yang jelas (didukung linter) menggunakan penangguhan hari ini yang terikat ke blok fungsi. Ketika blok fungsi keluar, sumber daya dibebaskan. Mengandalkan pengumpul sampah tidak memberikan jaminan bahwa Anda tidak akan menghabiskan sumber daya (standar batas penanganan file terbuka yang khas dapat antara 1k dan 4k) - yang mudah dilampaui dengan filepath.Walk sederhana yang tidak menutup file statistiknya.

Singkatnya saya pikir sintaks ini seperti yang diterapkan menawarkan risiko halus dalam manajemen sumber daya di Go karena tidak memiliki ctor/dtor dan bergantung pada mesin GC tingkat rendah yang jauh dari blok kode untuk mencegah kebocoran sumber daya. Mengubah sesuatu yang tampaknya tidak berbahaya menjadi kondisi kesalahan potensial (terlalu banyak file yang terbuka).

var n int
for _, name in try(os.Readdir(...)) {
   n += try(getSize(name))
}
func getSize(name string) (int, error) {
   return try(try(os.Open(name)).Stat()).Size
}

edit:
Untuk kendala, saya benar-benar berpikir jika itu hanya valid di sisi kanan tugas yang akan lebih baik daripada mengatakan 1 per baris, karena a, b := try(get("a")), try(get("b")) cukup masuk akal. Tapi itu masih menyisakan kemampuan untuk melakukan try(os.Open(name)).Stat() - yang jika Anda membuat try() batal, tetapi hanya ketika tidak berada di RHS tugas, Anda ditinggalkan dengan sesuatu yang tidak terlalu berfungsi seperti di semua.

@cstockton wow penemuan hebat!

Rust sebenarnya memiliki makro yang mirip ( ? jika saya ingat dengan benar) yang melakukan persis apa yang dimaksudkan try , tetapi mereka memiliki raii yang tepat di sana, jadi itu bukan masalah dalam bahasa itu dan masalah besar lubang dalam kasus kami

@sanbornm ya, menyimpan setengah dari internet di repo Anda sepertinya memang ide yang bagus.

Finishing Touch

Karena seseorang menyebutkan utilitas yang akan menghitung jumlah tempat di mana try akan menghemat waktu/usaha saya, saya memutuskan untuk menjalankannya di proyek kerja terbesar saya, ditambah semua yang lain di direktori GOPATH GitHub lama saya.

| Proyek | LOK* | coba kandidat |
|----------|------|----------------|
| kal1 | 2047 | 3 |
| pompa1 | 1030 | 0 |
| dokumen1 | 4576 | 8 |
| pelukan | 604 | 1 |
| yang lainnya | 8452 | 23 |

  • Buka kode saja, tidak termasuk komentar, menurut utilitas cloc .

Ingatlah bahwa konten "segalanya" mencakup peretasan cepat dan kode yang saya tulis ketika saya belajar Go.

Kesimpulan keseluruhan saya adalah bahwa setidaknya bagi saya, proposal try tidak akan membantu merampingkan penanganan kesalahan saya ke tingkat yang bermanfaat.

Alasan terbesar saya suka pergi adalah, spesifikasinya membatasi pembuat kode ke sebagian kecil sintaks yang tersedia untuk bahasa lain. Karena ini adalah kumpulan fitur yang kecil, mudah untuk mempelajari seluruh rangkaian fitur. Pengembang masa depan mungkin dapat melihat kode saya dan mengetahui apa yang saya lakukan. Setiap hal baru yang ditambahkan ke bahasa mengurangi kemungkinan pengembang masa depan mengetahui hal itu. Ekstrem lereng licin adalah bahasa yang kerumitannya membuat sulit untuk grok, seperti C++ atau scala.
Saya ingin melihat tidak ada penambahan sintaks untuk go 1. Letakkan di go 2 sebagai gantinya.

@miekg tolong tambahkan tautan ini https://github.com/golang/go/issues/32825#issuecomment -506882164 ke dalam proposal. Contoh tersebut sepenuhnya mendiskualifikasi seluruh gagasan dari kata kunci try .

image

Saya sangat setuju dengan membiarkannya apa adanya. Ini agak terlalu bertele-tele tetapi cukup mudah untuk diikuti.

Jika saya bisa mengurangi

if err := foo.x(a, b); err != nil {
  return err
}

if err := foo.y(); err != nil {
  return err
}

if err := foo.z(c); err != nil {
  return err
}

untuk sesuatu seperti

if err := check foo.x(a, b), foo.y(), foo.z(c); err != nil {
  return err
}

mungkin juga akan lebih bagus tanpa mengubah idiom terlalu banyak IMHO.

Jika Anda berbicara tentang tipe "Mungkin", itu membutuhkan tipe varian terlebih dahulu.

Mari kita pertahankan if err != nil itu berfungsi, jelas, itu benar-benar tidak bertele-tele, dan masuk akal dalam aliran kode. Saat Anda membaca kode dengan konstruksi ini, Anda tahu apa yang akan dilakukannya.
Mari kita simpan, jangan tambahkan try

Ketika saya membaca kode, saya ingin baris yang melakukan pekerjaan itu dapat dibaca dengan jelas, tanpa atau dengan penanganan kesalahan yang minimal.

3 huruf 'err' pada level yang sama dapat saya terima. Saya tidak ingin beberapa fungsi 'periksa' membungkus kode penting, karena kode penting akan berada di tingkat kedua (ingat cadel?), Dan saya tidak ingin baris 'coba' sebelumnya, karena kode penting akan menjorok dan pada baris kedua.

res, err := begin_job()
jika salah != nihil {
menangani_kesalahan()
}

err = lanjutkan_pekerjaan(res)
jika salah != nihil {
menangani_kesalahan()
}

Dengan kode ini, Anda dapat membaca alur kasus non-kesalahan dengan membaca baris pertama blok (seperti yang saya baca judul dokumen ketika saya harus membacanya dengan cepat)

Karena seseorang menyebutkan utilitas yang akan menghitung jumlah tempat di mana try akan menghemat waktu/usaha saya, saya memutuskan untuk menjalankannya di proyek kerja terbesar saya, ditambah semua yang lain di direktori GOPATH GitHub lama saya.

Project LOC* coba kandidat
kal1 2047 3
pompa1 1030 0
dokumen1 4576 8
pelukan 604 1
yang lainnya 8452 23

  • Buka kode saja, tidak termasuk komentar, menurut utilitas cloc .

Saya pikir try lebih dibutuhkan dalam program yang lebih besar. Hanya menggambar dari memori, saya pikir program dengan ukuran LOC sekitar 15-20k ke atas membutuhkannya lebih banyak karena saat itulah Anda mungkin mulai mendapatkan lapisan yang hanya perlu meneruskan kesalahan karena mereka ditentukan dengan tepat dan ditangani dalam sistem tertutup oleh baik sisi pengirim maupun penerima. Itu sangat tergantung pada jenis program apa itu. Saya mungkin juga tidak akan menggunakan banyak percobaan dalam program yang lebih kecil

Saya pikir try lebih dibutuhkan dalam program yang lebih besar.

Poin bagus. Saya mencoba tryhard pada heptio/contour, 28.7k baris teks sumber, tryhard menemukan 12 substitusi.

Saya pikir try lebih dibutuhkan dalam program yang lebih besar.

Poin bagus. Saya mencoba tryhard pada heptio/contour, 28.7k baris teks sumber, tryhard menemukan 12 substitusi.

WOW! 12 vs 28.7K baris, ini benar-benar membutuhkan kata kunci khusus!

Nah, saya lebih tertarik dengan POV Anda tentang ini :

stat := try(try(os.Open(fileName)).Stat())

Saya pikir itu lebih umum jika program Anda sedikit lebih monolitik dan bukan bagian dari integrasi layanan antara banyak layanan. Ketika saya hanya mencari fmt.errorf atau errors di github pada repositori itu ( heptio/contour ) hanya ada sedikit hasil sehingga sulit untuk mendapatkan gambaran umum singkat.. mengatakan itu mungkin sangat bervariasi dari program ke program, bahkan untuk program yang lebih besar.

Katakanlah Anda memiliki satu program yang tidak menggunakan banyak perpustakaan eksternal. Kemudian Anda dapat memiliki AuthorizationError tertentu (dan Anda tahu semua kesalahan yang dikembalikan cukup spesifik dengan kesalahan io apa pun yang sudah ditangani dan dibungkus) yang sudah berisi data meta pengguna Anda dan dapat disebarkan tanpa mengubah beberapa lapisan tanpa banyak perubahan pada hal-hal yang sebenarnya perlu untuk menangani mereka sampai lapisan permintaan.

Saya pikir itu lebih umum jika program Anda sedikit lebih monolitik dan bukan bagian dari integrasi layanan antara banyak layanan. Ketika saya hanya mencari fmt.errorf atau errors di github pada repositori itu hanya ada sedikit hasil sehingga sulit untuk mendapatkan gambaran umum singkat .. Tapi seperti yang saya katakan itu mungkin sangat bervariasi dari program untuk memprogram, bahkan untuk program yang lebih besar.

Katakanlah Anda memiliki satu program yang tidak menggunakan banyak perpustakaan eksternal. Kemudian Anda dapat memiliki AuthorizationError tertentu yang sudah berisi data meta pengguna Anda dan dapat disebarkan tanpa mengubah beberapa lapisan tanpa banyak perubahan pada hal-hal yang benar-benar perlu ditangani hingga lapisan permintaan.

Anda tidak mendapatkan ide. Anotasi adalah untuk dengan mudah menemukan cara kesalahan terjadi. Kami juga memiliki os.NotExist tetapi ini bukan petunjuk yang bagus tentang jalur kesalahan.

@thomasf di sini adalah titik data lain, dari salinan kerja juju/juju yang berumur beberapa tahun,

529628 baris sumber, tryhard menemukan 1763 (0,3%) pengganti.

Ya, tentu. Karena Anda telah terlibat dengan keduanya, mereka mungkin bukan contoh yang bagus tentang cara yang berbeda untuk menulis program. Saya bahkan tidak punya waktu untuk mencoba atm program tryhard dan bahkan lebih sedikit menjalankannya dengan benar di berbagai sumber (yang mungkin tidak mungkin dikumpulkan karena menghilangkan kode sumber tertutup jika dikumpulkan melalui github)

529628 baris sumber, tryhard menemukan 1763 (0,3%) pengganti.

Seperti yang dikatakan seseorang (perlu kutipan) dengan bijak, try tidak membuatnya lebih mudah untuk menangani kesalahan. Itu membuatnya lebih mudah untuk tidak menangani mereka.

Jika Anda menganalisis kode dan menemukan banyak pengganti try , semua yang memberitahu Anda adalah bahwa kode tidak melakukan apa pun dengan kesalahan kecuali mengembalikannya. Itu mungkin bukan kode yang bagus. Haruskah kita memudahkan orang menjadi malas dan tidak khawatir tentang kesalahan? Bukankah itu salah satu alasan Go tidak memiliki pengecualian, untuk menghindari hal itu?

Saya tidak akan mengambil posisi untuk itu. Namun, apa yang saya temukan adalah sedikit bukti pendukung yang menunjukkan bahwa

A. ada banyak lokasi di mana try berlaku untuk basis kode go yang ada
B. penanganan kesalahan secara umum merupakan bagian yang signifikan dari SLOC, berdasarkan pengukuran saya sendiri dan angka yang diperdebatkan oleh tim Go, ref https://youtu.be/RIvL2ONhFBI?t=440 kode waktu 07:26

Jika Anda menganalisis kode dan menemukan banyak pengganti try , semua yang memberi tahu Anda adalah bahwa kode tidak melakukan apa pun dengan kesalahan kecuali mengembalikannya. Itu mungkin bukan kode yang bagus. Haruskah kita memudahkan orang menjadi malas dan tidak khawatir tentang kesalahan? Bukankah itu salah satu alasan Go tidak memiliki pengecualian, untuk menghindari hal itu?

  1. Anda membuat penilaian nilai tentang kode teoretis yang tidak Anda ketahui yang bukan kebiasaan yang baik.
  2. Saya tidak melihat bagaimana try lebih mudah disalahgunakan daripada yang kita miliki sekarang, go tidak memiliki fitur untuk menegakkan penanganan kesalahan dan sudah sangat mudah untuk melewatinya. Bagi saya try adalah tentang membuat kode lebih mudah dibaca JIKA tidak perlu menangani kesalahan.

Mungkin tidak perlu try karena itu tidak akan dibutuhkan di banyak tempat, tapi mari kita menghibur ide dan membuat kasus penggunaan daripada hanya menjadi marah tentang hal itu...

Saya sendiri tidak dapat memikirkan banyak situasi praktis bagaimana saya akan menggunakannya tetapi itu juga belum ada sehingga sulit untuk mengatakan apakah saya akan merancang beberapa hal secara berbeda jika memang ada.. Satu hal yang terlintas dalam pikiran adalah bahwa saya mungkin lakukan adalah mengelompokkan sejumlah tindakan dalam fungsi anonim seperti ini menggunakan coba dan masih menangani kesalahan sebelum mengembalikannya ke pemanggil. Itu bisa membuat beberapa kode lebih mudah dibaca.

var v1, v3 string
if err := func() error {
    try(onething())
    v = try(twothing())
    try(otherthing())
    v3 = try(somethingg())
}(); err != nil {
  ... handle error...
}

Saya pikir mungkin ide yang baik pada saat ini untuk menulis situs web untuk menyimpan data untuk tryhard pada paket yang berbeda dan memvisualisasikannya. Mungkin memodifikasi sedikit golang/gddo (godoc.org) dapat melakukan pekerjaan itu.

Saya lebih suka meninggalkan if err != nil sendirian. Tetapi jika kita harus menambahkan sesuatu untuk penanganan kesalahan, berikut adalah proposal baru yang menambahkan kata kunci throws untuk itu.

32852

Tanpa mengulangi beberapa argumen yang sudah dijelaskan di sini, saya menggemakan sentimen untuk membiarkan if err != nil apa adanya.

Perspektif yang dapat saya tawarkan adalah sebagai berikut: Sebagai seseorang yang telah mengajar Go ke ratusan pendatang baru (baik ke pemrograman dan Go dari bahasa lain), if err != nil tidak pernah menjadi masalah bagi mereka. Pemrogram berpengalaman di bengkel saya merasa tidak biasa pada awalnya tetapi dengan cepat belajar untuk menyukai sifat eksplisit dari penanganan kesalahan di Go.

Ada kekhawatiran yang lebih besar yang dapat kami atasi dalam bahasa tersebut dan reaksi yang jelas dari komunitas terhadap masalah ini mengatakan bahwa if err != nil bukan salah satunya.

Go sempurna untuk banyak alasan. Kepala di antara mereka adalah "jika err != nil". Ini mungkin tampak bertele-tele, tetapi bagi orang yang belajar kode, ini memudahkan untuk men-debug kode Anda dan memperbaiki kode.

@davecheney

Saya tidak akan mengambil posisi untuk itu. Namun, apa yang saya temukan adalah sedikit bukti pendukung yang menunjukkan bahwa

A. ada banyak lokasi di mana try berlaku untuk basis kode go yang ada
B. penanganan kesalahan secara umum merupakan bagian yang signifikan dari SLOC, berdasarkan pengukuran saya sendiri dan angka yang diperdebatkan oleh tim Go, ref https://youtu.be/RIvL2ONhFBI?t=440 kode waktu 07:26

Saya khawatir bahwa dalam iklim saat ini setiap contoh yang kami temukan akan diabaikan begitu saja sebagai "mungkin itu bukan kode yang baik".

Berikut ini contohnya:

llorllale:~/go/src/github.com/hyperledger/fabric$ cloc --exclude-dir=vendor .
    2406 text files.
    2256 unique files.                                          
    3130 files ignored.

http://cloc.sourceforge.net v 1.60  T=6.69 s (272.8 files/s, 58350.9 lines/s)
--------------------------------------------------------------------------------
Language                      files          blank        comment           code
--------------------------------------------------------------------------------
Go                             1751          54365          34149         294005
YAML                             35            547           2171           2060
Bourne Shell                     26            354            325           1312
make                              3            135             96            418
CSS                               1             40             14            140
HTML                              3              7              5             63
Python                            1             50            103             57
Bourne Again Shell                1              1              6             50
Java                              3              7              4             26
XML                               2              1              4              2
--------------------------------------------------------------------------------
SUM:                           1826          55507          36877         298133
--------------------------------------------------------------------------------
llorllale:~/go/src/github.com/hyperledger/fabric$ tryhard -l . | grep -v vendor | less | wc -l
1417

Sejujurnya, data tentang jumlah lokasi yang ditemukan dapat dikacaukan oleh konvensi yang memerlukan kesalahan pembungkusan. Misalnya, jika konvensi perusahaan Anda adalah untuk

if err != nil {
   return errors.Wrap(err) 
} 

...
if err != nil {
   return errgo.Notef(err, "error doing x") 
} 

yang tidak akan dilaporkan oleh tryhard.

Kami memiliki konvensi seperti itu di perusahaan saya. Melakukan pencarian dan penggantian sederhana untuk mengembalikannya ke pengembalian kesalahan telanjang memberi saya hasil ini:

Language                             files          blank        comment           code
---------------------------------------------------------------------------------------
Go                                    2488          40317          15901         297038

tryhard melaporkan 2736 penggantian, tetapi melakukan tinjauan manual terhadap pembungkus yang tersisa sepertinya kurang terhitung sekitar tahun 1850, jadi saya memperkirakan total ~4500 try penggunaan dalam basis kode 300k baris kami.

(Secara pribadi, saya mendukung kejelasan penanganan kesalahan saat ini dan tidak keberatan.)

Misalnya, jika konvensi perusahaan Anda adalah untuk
[bungkus kesalahan dengan pesan khusus]
yang tidak akan dilaporkan oleh tryhard.

Itulah intinya — proposal try hanya menyederhanakan pengembalian telanjang if err != nil return err , tidak mendukung kesalahan pembungkusan dengan pesan dan konteks khusus.

Satu-satunya pengulangan if err != nil saya yakini dapat diperbaiki karena juga harus menentukan nilai nol dari nilai pengembalian lainnya. Bahasa dapat diperbarui untuk menghindari itu. Sebagai contoh:

Di Go hari ini, jika saya memiliki fungsi dengan tanda tangan ini:

func add(x, y string) (int, error)

Di suatu tempat dalam fungsi, saya harus menulis:

func add(x, y string) (int, error) {
    // ...
    if err != nil {
        return 0, err
    }

Memaksa penulis untuk mengulang nilai nol yang sama di seluruh fungsi.

Akan jauh lebih mudah (dan dengan sedikit biaya untuk kesalahan verbositas dan keterbacaan) jika bahasa dapat secara otomatis mengisi nilai nol untuk nilai pengembalian non-kesalahan:

func add(x, y string) (int, error) {
    // ...
    if err != nil {
        return ..., err
    }
    // ...
}
func main() {
    add("8", "beep") // returns 0, error(`strconv.ParseInt: parsing "beep": invalid syntax`)
}

Saya dapat mengatakan dari pengalaman dengan banyak kode yang berinteraksi dengan permintaan dan panggilan DB, harus mengulangi nilai nol di seluruh fungsi adalah satu-satunya negatif dari penanganan kesalahan gaya-Go. Kalau tidak, saya setuju dengan sentimen proposal ini: Tinggalkan if err != nil saja!

Catatan: ya, nilai kembalian bernama dapat _sort of_ menyelesaikan ini (https://play.golang.org/p/MLV8Y52HUBY), tetapi setelah menerapkan beberapa fungsi dalam basis kode saya sendiri menggunakan teknik ini, saya diingatkan betapa -gun bernama nilai kembali adalah; Saya selalu berakhir membayangi nilai pengembalian bernama.

Misalnya, jika konvensi perusahaan Anda adalah untuk
[bungkus kesalahan dengan pesan khusus]
yang tidak akan dilaporkan oleh tryhard.

Itulah intinya — proposal try hanya menyederhanakan pengembalian telanjang if err != nil return err , tidak mendukung kesalahan pembungkusan dengan pesan dan konteks khusus.

Itu benar, saya sedang memikirkan varian yang memungkinkan menambahkan string deskriptif. Sebagian besar (~4000 / 4500) dari pengembalian kesalahan kami adalah errgo.Mask(err) tanpa konteks, yang saya pertimbangkan setara dengan tanpa deskripsi try() , tetapi saat ini akan menjadi pengurangan fungsionalitas karena errgo menambahkan informasi tumpukan dan coba tidak (belum).

@ianlancetaylor ada proposal di sini. @miekg mengusulkan agar Anda sebagai salah satu pemimpin bahasa kami tidak lagi mengejar penggantian if err != nil dengan beberapa konstruksi lain yang bertentangan dengan semangat penanganan kesalahan seperti yang diputuskan oleh Penulis Go asli. Bagi saya pribadi, rasanya seperti Anda mencoba menegaskan tidak pentingnya permintaan ini dengan memindahkannya ke golang-nuts alih-alih memperlakukannya seperti proposal kami yang lain. Itu mungkin bukan niat Anda, tetapi itu adalah dampak yang saya rasakan.

Metode penanganan kesalahan kami unik, dan saya yakin ini merupakan nilai tambah yang sangat besar dibandingkan bahasa lain. Ini benar-benar mengubah cara saya berpikir tentang kesalahan dalam sistem yang saya buat, dan sebagai hasilnya saya menjadi insinyur perangkat lunak yang lebih kuat. Saya tidak ingin kita menjadi panutan bagi minoritas, atau orang luar, demi mendapatkan lebih banyak pengembang Go. Saya pikir kita harus mengambil garis keras pada hal-hal tertentu, dengan cara kita memilih untuk menangani kesalahan menjadi salah satunya karena itu membuat kita lebih baik dengan memperdagangkan singkatnya kode.

Ini adalah kesempatan bagi tim di dalam Google untuk membangun lebih banyak kepercayaan dan keyakinan dengan komunitas, atau untuk melanjutkan lintasan yang sedang kita jalani saat ini yang tidak baik untuk bahasa, ekosistem, atau penggunanya.

Saya meminta Tim Go menerima proposal ini apa adanya, sambil terus mengejar iterasi bahasa lain yang tidak terkait yang merupakan nilai tambah yang lebih jelas.

Pelacak mungkin tidak memiliki threading, tetapi saya pribadi lebih suka memiliki jaminan bahwa proposal ini ditanggapi dalam kapasitas resmi dan tidak diturunkan ke grup Google di mana ia dapat menghilang secara diam-diam ke dalam ketidakjelasan.

Topiknya sudah dibahas di grup Google juga.

Versi #32437 saat ini tidak memuaskan. Try() bawaan menyembunyikan banyak jalur eksekusi ke mata yang tidak terlatih. Proposal asli dengan cek dan pegangan sangat bisa dimengerti dan kata kunci cek menonjol.

Sekarang, try() bawaan terlihat seperti fungsi - tidak jelas bahwa itu dapat mengubah aliran kontrol. Kami juga memiliki panic(), tetapi (saya percaya) selalu pada barisnya sendiri, memiliki nama yang menonjol dan penggunaannya jarang. try() di sisi lain, bisa bersembunyi di dalam ekspresi yang kompleks.

@theckman Robert telah merancang iterasi pertama Go dengan Rob dan Ken, dan Robert dan Russ telah bergabung dengan tim lebih awal. Mereka telah mengerjakan Go sejak awal. Saya pikir kita dapat mempercayai mereka untuk mengetahui apakah proposal "bertentangan dengan semangat penanganan kesalahan seperti yang diputuskan oleh Penulis Go asli".

Saya tidak menyukai prinsip proposal yang akan membekukan penanganan kesalahan seperti sekarang ini. Proposal seperti itu akan melarang semua proposal masa depan tentang topik ini.

Mengapa tidak menerima saja untuk mengulangi desainnya? Kami memiliki proposal cek/tangani. Tetapi beberapa kekurangan dibahas. Hal ini menyebabkan proposal percobaan. Beberapa kelemahan dari proposal ini dibahas sekarang. Mungkin ini akan mengarah ke proposal lain yang lebih baik, sampai pendekatan yang tepat ditemukan.

Metode penanganan kesalahan kami unik

Penanganan kesalahan di Rust secara konseptual mirip dengan apa yang kami lakukan di Go (kesalahan adalah nilai, aliran kontrol eksplisit, kecuali kami menggunakan beberapa nilai pengembalian saat mereka menggunakan tipe jumlah sebagai gantinya). Rust memiliki masalah yang sama dengan Go dengan penanganan kesalahan verbose. Ini membuat Rust menambahkan percobaan! makro, dan akhirnya ? operator. Saya akan mengatakan komunitas Rust bahkan lebih ketat daripada komunitas Go mengenai penanganan kesalahan (RFC penanganan kesalahan dan diskusi mencerahkan). Mereka telah menemukan cara untuk mengurangi verbositas penanganan kesalahan tanpa kemiringan yang licin dari penanganan kesalahan yang buruk. Saya yakin kita juga bisa.

lintasan kita saat ini yang tidak baik untuk bahasa, ekosistem, atau penggunanya

Apa yang kamu bicarakan? Go terus meningkat. Sungguh menakjubkan memiliki akses ke bahasa, peralatan, dan dokumentasi yang begitu hebat secara gratis (seperti dalam kebebasan berbicara).

@theckman Robert telah merancang iterasi pertama Go dengan Rob dan Ken, dan Robert dan Russ telah bergabung dengan tim lebih awal. Mereka telah mengerjakan Go sejak awal. Saya pikir kita dapat mempercayai mereka untuk mengetahui apakah proposal "bertentangan dengan semangat penanganan kesalahan seperti yang diputuskan oleh Penulis Go asli".

Saya tidak menyukai prinsip proposal yang akan membekukan penanganan kesalahan seperti sekarang ini. Proposal seperti itu akan melarang semua proposal masa depan tentang topik ini.

Mengapa tidak menerima saja untuk mengulangi desainnya? Kami memiliki proposal cek/tangani. Tetapi beberapa kekurangan dibahas. Hal ini menyebabkan proposal percobaan. Beberapa kelemahan dari proposal ini dibahas sekarang. Mungkin ini akan mengarah ke proposal lain yang lebih baik, sampai pendekatan yang tepat ditemukan.

Metode penanganan kesalahan kami unik

Penanganan kesalahan di Rust secara konseptual mirip dengan apa yang kami lakukan di Go (kesalahan adalah nilai, aliran kontrol eksplisit, kecuali kami menggunakan beberapa nilai pengembalian saat mereka menggunakan tipe jumlah sebagai gantinya). Rust memiliki masalah yang sama dengan Go dengan penanganan kesalahan verbose. Ini membuat Rust menambahkan percobaan! makro, dan akhirnya ? operator. Saya akan mengatakan komunitas Rust bahkan lebih ketat daripada komunitas Go mengenai penanganan kesalahan (RFC penanganan kesalahan dan diskusi mencerahkan). Mereka telah menemukan cara untuk mengurangi verbositas penanganan kesalahan tanpa kemiringan yang licin dari penanganan kesalahan yang buruk. Saya yakin kita juga bisa.

lintasan kita saat ini yang tidak baik untuk bahasa, ekosistem, atau penggunanya

Apa yang kamu bicarakan? Go terus meningkat. Sungguh menakjubkan memiliki akses ke bahasa, peralatan, dan dokumentasi yang begitu hebat secara gratis (seperti dalam kebebasan berbicara).

Sejarah perkembangan Rust menunjukkan orang-orang di baliknya tidak tahu apa yang mereka lakukan. Mereka pada dasarnya menyalin prinsip pemrosesan kesalahan dari Haskell, tetapi ini tidak cocok untuk pemrograman imperatif (dunia nyata?). Makro ? hanyalah solusi untuk sistem pemrosesan kesalahan yang awalnya gagal.

@ianlancetaylor ada proposal di sini. @miekg mengusulkan agar Anda sebagai salah satu pemimpin bahasa kami tidak lagi mengejar penggantian if err != nil dengan beberapa konstruksi lain yang bertentangan dengan semangat penanganan kesalahan seperti yang diputuskan oleh Penulis Go asli. Bagi saya pribadi, rasanya seperti Anda mencoba menegaskan tidak pentingnya permintaan ini dengan memindahkannya ke golang-nuts alih-alih memperlakukannya seperti proposal kami yang lain. Itu mungkin bukan niat Anda, tetapi itu adalah dampak yang saya rasakan.

Metode penanganan kesalahan kami unik, dan saya yakin ini merupakan nilai tambah yang sangat besar dibandingkan bahasa lain. Ini benar-benar mengubah cara saya berpikir tentang kesalahan dalam sistem yang saya buat, dan sebagai hasilnya saya menjadi insinyur perangkat lunak yang lebih kuat. Saya tidak ingin kita menjadi panutan bagi minoritas, atau orang luar, demi mendapatkan lebih banyak pengembang Go. Saya pikir kita harus mengambil garis keras pada hal-hal tertentu, dengan cara kita memilih untuk menangani kesalahan menjadi salah satunya karena itu membuat kita lebih baik dengan memperdagangkan singkatnya kode.

Ini adalah kesempatan bagi tim di dalam Google untuk membangun lebih banyak kepercayaan dan keyakinan dengan komunitas, atau untuk melanjutkan lintasan yang sedang kita jalani saat ini yang tidak baik untuk bahasa, ekosistem, atau penggunanya.

Saya meminta Tim Go menerima proposal ini apa adanya, sambil terus mengejar iterasi bahasa lain yang tidak terkait yang merupakan nilai tambah yang lebih jelas.

Mereka tidak dapat melakukan sesuatu yang serius dengan sistem tipe saat ini dari tahun 60-an. Mereka akhirnya harus meminjam ide tahun 80-an di Go 2.0 mereka

Apa yang kamu bicarakan? Go terus meningkat. Sungguh menakjubkan memiliki akses ke bahasa, peralatan, dan dokumentasi yang begitu hebat secara gratis (seperti dalam kebebasan berbicara).

@ngrilly bagian terakhir itu mungkin untuk diskusi yang lebih besar. Tanpa menggagalkan proposal ini, tetapi menutup komentar itu, ada sentimen ketidaksejajaran yang berkembang antara pengguna dan kepemimpinan dalam komunitas/ekosistem.

Untuk sisa diskusi, saya tidak berpikir menambahkan lebih banyak overhead kognitif ke sintaks adalah kemenangan. Saya senang mereka menemukan sesuatu yang berhasil untuk mereka, kami bukan mereka.

Saya baru saja membuka proposal untuk pernyataan inline if: https://github.com/golang/go/issues/32860

Referensi: https://github.com/golang/go/issues/32825#issuecomment-506707539

Betapa dunia ini akan menjadi lebih baik jika setiap orang mengirimkan proposal mereka tentang fitur golang 2.0 baru apa pun yang mereka sangat ingin miliki, juga akan menyediakan cabang dari https://github.com/golang/go (dan apa pun lainnya repositori yang diperlukan) yang mengimplementasikan proposal itu.

Apakah Anda tidak setuju?

@av86743 Tampaknya di luar cakupan proposal ini. Silakan ajukan Proposal yang menyarankan tindakan tersebut.

Saya melihat beberapa tantangan dengan itu, seperti risiko banyak usaha yang sia-sia sebelum seseorang menolaknya berdasarkan sesuatu dalam dokumen proposal itu sendiri. Kemudian Anda menghabiskan semua waktu itu pada garpu yang bahkan tidak akan ditinjau.

bagaimana dengan sintaks ini:

# call error handler
try callFunction(), errorHandler()

# error handler with anonymous function
variable := try callSomething(), func(err *Error) { # error handling }

@theckman Saya minta maaf jika sepertinya saran saya untuk memindahkan diskusi ini ke tempat lain membuatnya tampak tidak penting. Saya menjelaskan alasan saya dalam permintaan saya, dan saya yakin itu masih berlaku. Tim Go mempertimbangkan diskusi milis serta proposal.

Karena Anda menyebutkan "Penulis Go yang asli", saya pikir perlu disebutkan bahwa proposal "coba" dibuat oleh @griesemer yang merupakan salah satu dari tiga penulis Go asli.

Saya sangat setuju dengan usulan ini, menurut saya yang perlu diubah hanyalah go fmt, make go fmt untuk mengizinkan satu baris pernyataan if.

Saya benar-benar ingin satu baris

if err != nil { return wrappedErr{err} }

bukannya tiga baris

if err != nil {
    return wrappedErr{err}
}

@av86743 Tampaknya di luar cakupan proposal ini. Silakan ajukan Proposal yang menyarankan tindakan tersebut.

@theckman Anda memberi tahu saya apa yang harus dilakukan, dan ini bukan hanya tidak sopan, tetapi juga kasar. Anda dapat mencoba memposisikan diri Anda dengan cara apa pun yang Anda pilih, namun baik saya sendiri maupun, mungkin, orang lain di sini adalah monyet "pergi menjemput" Anda untuk melompat ketika Anda mengatakannya.

Saya melihat beberapa tantangan dengan itu, seperti risiko banyak usaha yang sia-sia sebelum seseorang menolaknya berdasarkan sesuatu dalam dokumen proposal itu sendiri. Kemudian Anda menghabiskan semua waktu itu pada garpu yang bahkan tidak akan ditinjau.

Itu hanya akan menjadi "usaha yang sia-sia" untuk [... _deskripsi dalam bahasa yang sepenuhnya tepat dihilangkan demi singkatnya_ ...].

Namun, untuk seorang pembuat kode, itu akan menjadi latihan yang sepele, tetapi bermanfaat dan, pada saat yang sama, layanan untuk komunitas Go.

@ av86743 Saya pikir apa yang Anda sarankan adalah ide yang menarik dan saya tidak ingin itu hilang sebagai komentar dalam masalah yang tidak terkait. Jika Anda tidak tertarik untuk membahasnya dalam kapasitas resmi untuk dipertimbangkan, saya minta maaf karena menganjurkan agar Anda mengangkat masalah terpisah.

Meskipun proposal khusus ini berasal dari @griesemer , saya merasa sulit untuk percaya bahwa dia telah mendidih dengan kemarahan batin selama sepuluh tahun tentang verbositas pengembalian kesalahan yang tidak terungkap di Go. Namun, dia adalah seorang insinyur yang sangat baik, dan para insinyur datang dengan solusi untuk masalah (yang dirasakan); sangat sulit untuk menghentikan mereka. Kami _suka_ memecahkan masalah. Mengendus masalah saja sudah cukup bagi kita untuk mulai memunculkan segala macam ide. Begitu proses berpikir itu cukup maju, sulit bagi kita untuk melepaskan solusi yang diduga secara emosional dan menganggap bahwa _mungkin itu sebenarnya bukan masalah_. Lagi pula, kami punya bayi, secara intelektual, dan tidak mudah untuk meninggalkannya begitu saja.

Untuk apa nilainya, kecurigaan pribadi saya adalah bahwa proses penalaran tim Go tentang hal ini telah berjalan seperti:

  1. Go sangat populer dan digunakan secara luas, sehingga ribuan orang tentu saja memiliki komentar, saran, dan keluhan tentangnya.
  2. Anda hanya bisa menghalangi begitu lama. Tim Go merasa di bawah tekanan besar untuk melakukan _sesuatu_ tentang semua kebisingan dari komunitas.
  3. Ini adalah sesuatu.

bagaimana kalau menambahkan fungsi catch() di defer to catch jika percobaan ditemukan beberapa kesalahan seperti memulihkan().
contoh:

func doSomthing()(err error){
    //return error
}

func main(){
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

    try doSomthing()
}

pada banyak fungsi

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

   try{
    file1 := open("file1")
    defer file1.Close()
    file2 := open("file2")
    defer file2.Close()
   }
   //without try
    file3,err := open("file3")
    defer file3.Close()
 }

bagaimana kalau menambahkan fungsi catch() di defer to catch jika percobaan ditemukan beberapa kesalahan seperti memulihkan().
contoh:

func doSomthing()(err error){
    //return error
}

func main(){
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

    try doSomthing()
}

pada banyak fungsi

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

   try{
  file1 := open("file1")
  defer file1.Close()
  file2 := open("file2")
  defer file2.Close()
   }
   //without try
    file3,err := open("file3")
    defer file3.Close()
 }

Bagaimana ini membantu menangani setiap kesalahan dengan cara yang terpisah?

Beberapa klarifikasi:

  1. Proposal try tidak memperkenalkan sintaks baru atau kata kunci baru, bertentangan dengan apa yang diklaim oleh beberapa orang di utas ini. Itu hanya memperkenalkan built-in baru, tentang perubahan paling minimal yang mungkin bisa dilakukan untuk menambahkan fungsionalitas baru. Harap tepat ketika membahas ini, karena itu penting. Ada perbedaan besar antara menambahkan sintaks baru dan kata kunci baru, dan built-in. Yang pertama adalah perubahan besar, yang terakhir adalah tambahan yang relatif kecil. Apa yang disarankan oleh proposal try adalah tambahan yang relatif kecil.

  2. Saya setuju dengan @ianlancetaylor bahwa diskusi ini lebih baik diadakan di tempat lain (golang-nuts). Tidak ada usulan di sini.

  3. Memang, @bitfield , saya tidak memiliki "kemarahan batin tentang verbositas pengembalian kesalahan yang dibuka di Go" , terima kasih :-) Tapi saya pikir pemeriksaan kesalahan lebih bertele-tele yang mungkin diperlukan; dan fakta bahwa sentimen yang sama telah diangkat oleh komunitas berulang kali adalah indikator yang jelas bahwa kami (tim Go) tidak sendirian dengan keyakinan ini. Saya tidak akan pergi sejauh mengatakan ada banyak tekanan untuk melakukan "sesuatu" - kami telah mengerjakan ini dan mematikannya untuk waktu yang lama sekarang, dan kami cukup puas menunggu pendekatan yang "benar" .

Proposal try adalah tentang solusi paling minimal yang kami temukan (dengan bantuan signifikan dari kontribusi komunitas) yang mengatasi masalah pemeriksaan kesalahan. Proposal try sangat eksplisit tentang fakta bahwa itu _tidak akan membantu sama sekali_ jika setiap pengujian kesalahan memerlukan penanganan kesalahan dengan cara tertentu. try hanya membantu ketika semua kesalahan dalam suatu fungsi diuji dan ditangani dengan cara yang sama (dan kemudian kami menyarankan untuk menggunakan defer ), atau ketika kesalahan tersebut dikembalikan. Sulit untuk lebih eksplisit di sini, tetapi mari kita ulangi apa yang dinyatakan oleh proposal : try tidak akan membantu dalam semua skenario kesalahan. Ini membantu dalam sejumlah besar kasus. Untuk yang lainnya, gunakan pernyataan if .

@griesemer try terlalu rawan kesalahan: tidak ada RAII di Go, jadi kami tidak bisa meninggalkan fungsi dalam banyak kasus.

@sirkon , saya tidak yakin bagaimana RAII relevan dengan diskusi ini. try mengganti pola if ..., err := f(); err != nil { return ..., err } dengan ... := try(f()) . Jika ada bug yang membebaskan sumber daya dengan menggunakan try , maka itu pasti ada sebelumnya juga. Pengenalan try tidak meningkatkan atau mencegah bug yang membebaskan sumber daya.

@sirkon , saya tidak yakin bagaimana RAII relevan dengan diskusi ini. try mengganti pola if ..., err := f(); err != nil { return ..., err } dengan ... := try(f()) . Jika ada bug yang membebaskan sumber daya dengan menggunakan try , maka itu pasti ada sebelumnya juga. Pengenalan try tidak meningkatkan atau mencegah bug yang membebaskan sumber daya.

Baca utasnya, ada contohnya:

info := try(try(os.Open(fileName)).Stat())

@sirkon Saya telah melihat contoh itu beberapa kali sekarang. Saya setuju bahwa itu menarik. Tapi mari kita pikirkan lebih jauh. try builtin yang diusulkan pada dasarnya adalah gula sintaksis untuk jenis boilerplate tertentu yang ditemukan dalam kode Go. Jadi kita bisa mengonversi contoh itu ke kode aslinya.

    f, err := os.Open(fileName)
    if err != nil {
        return err
    }
    info, err := f.Stat()
    if err != nil {
        return err
    }

Kode itu memiliki bug yang sama. Saya pasti pernah melihat kode seperti itu. Tidak jelas bagi saya bahwa try bawaan membuat bug itu lebih mudah ditulis atau lebih sulit dilihat.

[Sepertinya @ianlancetaylor baru saja mengalahkan saya.]

@sirkon Bug ini sudah mungkin, try atau tidak - Go tidak mencegah Anda menulis kode yang buruk. Atau membalikkan ini, menggunakan kode buruk sebagai alasan mengapa try tidak boleh diizinkan bukanlah argumen yang meyakinkan. Sebaliknya, go vet harus menandai kasus yang bermasalah.

defer adalah idiom Go untuk dibersihkan ketika suatu fungsi kembali, dan itu berfungsi dengan baik. Pendekatan yang benar di sini tentu saja adalah:

f := try(os.Open(filename))
defer f.Close()
info := try(f.Stat())

bandingkan ini dengan:

f, err := os.Open(filename)
if err != nil {
   return ..., err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
   return ..., err
}

Menggunakan try sumber berkonsentrasi pada perhatian utama: mendapatkan info file file. Menggunakan pendekatan tradisional, sebagian besar kode sumber memperhatikan kemungkinan kesalahan; dan itu semua sama. Bahkan jika kita ingin mendekorasi kesalahan, pendekatan try bekerja dengan baik:

defer errd.Wrap(&err, "failed to do X for %s", filename)
f := try(os.Open(filename))
defer f.Close()
info := try(f.Stat())

menggunakan sesuatu seperti paket errd (lihat edisi #32676).

@griesemer
Tinjauan kode diri saya di masa depan masih terus berteriak bahwa mekanisme aliran kontrol harus berada di jalurnya sendiri. Bisakah pendekatan ini valid (tanpa penegakan) dalam proposal saat ini? Selain keterbacaan, refactoring ke logika penanganan kesalahan yang lebih detail menjadi lebih mudah.

defer errd.Wrap(&err, "failed to do X for %s", filename)
f, err:= os.Open(filename)
try(err) // check is so much a better term
defer f.Close()
info, err := f.Stat()
try(err)

Juga, pendekatan ke handle terlihat bagus di sini, tetapi tidakkah banyak penundaan akan membuat kekacauan? Atau akankah ada sinkronisasi cakupan fungsi. Sekali hal (saya tidak melihat klarifikasi dalam masalah kesalahan)? Jika demikian, apakah fungsi anonim akan diberikan ruang lingkupnya sendiri? Dan membayangi... eesh - siapa yang pertama, apa yang kedua?

Ini semua terasa seperti akan ada dua "mode" penulisan kode Go. Katakan tidak begitu.

@griesemer Meskipun Anda benar, bug juga mungkin terjadi hari ini, saya sangat merasa itu akan menjadi lebih umum di masa depan dengan implementasi try saat ini. Seseorang yang berasal dari hampir _any_ bahasa populer yang saya dapat().think.Of(Has)Chaining().Of(Methods) tertanam ke dalam mereka untuk lebih baik atau lebih buruk. Semua bahasa ini menyediakan idiom mereka sendiri yang membuat polanya alami dan aman. Mereka menabrak penghalang jalan langsung dengan Go karena sistem tipe memaksa mereka untuk menetapkan setiap nilai dengan kondisi kegagalan yang menyertainya, tidak ada pola yang masuk akal untuk menghindari ini (atau proposal percobaan tidak akan ada).

Jika proposal ini diterima, mereka akan mencari cara untuk menghindari pelat boiler if err , yang memungkinkan mereka untuk menulis kode dengan cara yang mereka kenal. Kecuali mereka akan memiliki hampir satu dekade kode Go dalam jawaban stackoverflow, posting blog dll yang ditulis sebelum try dibuat. Mereka akan dengan cepat belajar untuk menghilangkan pernyataan err dan if dengan try. Mereka menginginkan ukuran file yang dapat mereka tempelkan kode yang dibungkus try hingga mereka dapat mengakses bidang yang diinginkan seperti Stat() dalam proposal percobaan. Itu adalah pola yang mereka gunakan sehingga wajar saja mereka menerapkannya saat menulis Go. Mengingat Go OS yang paling bertarget memperlakukan semuanya sebagai file, wajar untuk mengasumsikan lebih banyak kebocoran sumber daya akan terjadi.

Yang membawa saya ke mengapa saya sangat tidak setuju dengan pernyataan "Anda sudah bisa melakukan ini hari ini" - karena Anda tidak bisa. Tentu - Anda dapat membocorkan pegangan file. Tetapi Go tidak memberikan kesempatan kepada programmer untuk melewatkan pengidentifikasi dalam ruang lingkup dan dengan demikian juga membocorkan file. Setiap pengenal f dilewati adalah file handle yang bocor. Penggunaan fitur _memerlukan_ bahwa idiom menonjol tertentu dalam ekosistem Go rusak. Dengan demikian- memperkenalkan fitur seperti yang dirancang hari ini terbukti meningkatkan risiko kebocoran sumber daya di Go.

Yang mengatakan seperti yang saya sebutkan di https://github.com/golang/go/issues/32825#issuecomment -506882164 Saya sebenarnya akan mendukung try jika beberapa penyesuaian kecil dilakukan, saya pikir perubahannya akan menjadi menyambut tambahan bahasa. Yang saya pikir perlu coba adalah membuatnya hanya valid pada RHS dari suatu tugas dan tidak mengizinkan nilai pengembalian untuk dialamatkan. Jadikan contoh "baik" dari penggunaan coba (cenderung satu coba per baris) menjadi cara "satu-satunya" untuk menggunakan coba, yaitu:

info := try(try(os.Open(filename)).Stat()) // compiler error
f := try(os.Open(filename)) // valid
// we were forced to assign f, so we still have an identifier to Close (serve linters and users alike)
defer f.Close()
info := try(f.Stat())
a, b := try(strconv.Atoi("1")), try(strconv.Atoi("2")) // also valid 
a, b := try(strconv.Atoi("1"), strconv.Atoi("2")) // maybe?
a, b := try strconv.Atoi("1"), strconv.Atoi("2")

Saya pikir ini akan lebih cocok secara alami dalam bahasa, pertahankan semua manfaat saat ini dari try (selain menyarangkannya, jika Anda menganggapnya sebagai manfaat) tanpa kekurangan apa pun. Saya tidak berpikir nesting of try tidak membantu siapa pun, menghemat sangat sedikit, tetapi memberikan kemungkinan penyalahgunaan yang tidak terbatas. Saya tidak merasa sangat jahat hari ini, jadi ini yang terbaik yang bisa saya lakukan:

total := try(try(os.Open(filename)).Stat()).Size() + try(strconv.Atoi(try(ioutil.ReadAll(os.Stdin))))

Tapi _we_ akan memikirkan yang terburuk, jika Anda mengizinkan kami.

@daved Menempatkan try(err) pada baris kedua didukung sepenuhnya dengan proposal try : try hanya menginginkan argumen yang mengevaluasi satu atau lebih nilai di mana nilai terakhir adalah ketik error , yang secara alami puas ketika Anda menulis try(err) .

Saya tidak yakin saya mengikuti kekhawatiran Anda mengenai defer - jika diperlukan penangan yang berbeda, defer mungkin bukan pilihan yang tepat; sebagai gantinya if tradisional mungkin diperlukan (seperti yang dijelaskan dalam proposal).

@cstockton Saya setuju bahwa try bersarang bisa sangat bermasalah; tetapi saya juga percaya jika kita memiliki try , sebagian besar kode akan terlihat seperti contoh (valid) yang telah Anda berikan . Profesional tidak membuat kode dalam ruang hampa, mereka cenderung mengikuti panduan gaya, ulasan kode, dan praktik yang baik. Jadi saya tidak begitu peduli di sini (sangat mengetahui bahwa jika mungkin untuk menulis kode yang buruk atau salah, seseorang akan melakukannya - biarlah).

Untuk masalah gaya, kami tidak memberikan batasan seperti yang Anda sukai ke dalam bahasa - kami telah menggunakan go vet untuk itu. Pada akhirnya, untuk perangkat lunak tertulis efeknya sama. Tetapi dengan tidak memilikinya dalam bahasa, kita tidak mengikat diri kita sendiri. Sulit untuk mendapatkan batasan itu dengan benar, dan mereka membuat spesifikasi menjadi tidak perlu rumit. Jauh lebih mudah untuk menyesuaikan go vet dan membuatnya lebih pintar karena kita belajar lebih banyak daripada menyesuaikan bahasa.

@griesemer Terima kasih atas klarifikasinya. Dalam contoh kode, jika baris pertama adalah var err error , apakah pembungkus berpotensi memengaruhi kedua kesalahan yang diperiksa? Saya telah melihat pembicaraan tentang membayangi menjadi masalah yang mungkin ditangani di masa depan. Bagaimana/mungkin itu berhubungan dengan ini?

bagaimana kalau menambahkan fungsi catch() di defer to catch jika percobaan ditemukan beberapa kesalahan seperti memulihkan().
contoh:

func doSomthing()(err error){
    //return error
}

func main(){
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

    try doSomthing()
}

pada banyak fungsi

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

   try{
    file1 := open("file1")
    defer file1.Close()
    file2 := open("file2")
    defer file2.Close()
   }
   //without try
    file3,err := open("file3")
    defer file3.Close()
 }

Bagaimana ini membantu menangani setiap kesalahan dengan cara yang terpisah?

seperti pengguna lain berkomitmen

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

    file1 :=try open("file1")
    defer file1.Close()
    file2 :=try open("file2")
    defer file2.Close()

        //without try
       file3,err := open("file3")
       defer file3.Close()
 }

@daved Dalam contoh ini, asumsinya adalah bahwa err adalah nama dari hasil error . try akan selalu mengatur variabel kesalahan hasil itu, tidak peduli namanya (atau tidak ada nama). Jika Anda memiliki variabel lokal bernama err maka itu adalah variabel yang berbeda. Jika Anda ingin merujuk ke kesalahan hasil, itu harus memiliki nama yang berbeda. Perhatikan bahwa ini sudah menjadi kasus bahwa ini tidak valid:

func f(...) (..., err error) {
   var err error // << err already declared
   ...

Sebaliknya, jika Anda menulis:

func f(...) (..., err error) {
   a, b, ... err := g() // redeclaration of err
   ...

err dalam tugas sama dengan yang disebutkan dalam daftar parameter hasil. Tidak ada yang berbeda di sini dari apa yang sudah terjadi untuk waktu yang sangat lama.

PS: Kita mungkin harus berhenti membajak masalah ini untuk diskusi try dan kembali ke proposal asli - itu akan dibuka dan terbuka untuk diskusi besok (1 Juli) lagi.

@godcong Fungsi catch() (atau serupa) hanya akan memungkinkan Anda untuk mendapatkan kesalahan, bukan untuk mengaturnya (dan biasanya seseorang ingin mengatur kesalahan dari fungsi terlampir dalam fungsi yang ditangguhkan yang beroperasi sebagai penangan kesalahan) . Itu bisa dibuat bekerja dengan membuat catch() mengembalikan *error yang merupakan alamat dari nilai pengembalian kesalahan fungsi terlampir. Tetapi mengapa tidak menggunakan nama hasil kesalahan saja daripada menambahkan mekanisme baru ke bahasa? Lihat juga proposal try yang membahas hal ini.

Juga, lihat PS di atas .

@griesemer

Sulit untuk lebih eksplisit di sini, tetapi mari kita ulangi apa yang dinyatakan proposal: coba tidak akan membantu dalam semua skenario kesalahan. Ini membantu dalam sejumlah besar kasus. Untuk yang lainnya, gunakan pernyataan if.

Saya pikir ini adalah kelemahan fatal dari proposal try() : di mana sebelumnya ada satu dan hanya satu cara untuk melakukan pengecekan kesalahan, sekarang akan ada dua, bercampur di seluruh basis kode. Juga, setidaknya untuk basis kode yang saya kerjakan, kurang dari 20% dari if err != nil dapat diganti dengan try() , yang meskipun tidak signifikan, sepertinya tidak cukup berharga untuk membuat terbagi dalam gaya penanganan kesalahan.

Secara pribadi saya lebih suka konstruksi penanganan kesalahan yang cukup kuat untuk menggantikan 95% dari semua kasus if err != nil sebagai gantinya. Saya pikir itu juga yang disukai banyak orang.

@griesemer Saya setuju bahwa orang akan belajar dan perkakas akan menjadi suatu keharusan karena panduan gaya, praktik yang baik, contoh, dokumentasi, dan sebagainya yang Anda rujuk semuanya akan ketinggalan zaman. Saya pikir sudah jelas bahwa try seperti yang diusulkan saat ini memperkenalkan cara-cara baru yang halus untuk menulis perangkat lunak yang salah. Apa yang tidak jelas adalah bagaimana mengabaikan fakta ini di bawah premis bahwa orang selalu dapat menulis perangkat lunak yang salah adalah argumen tandingan yang valid?

Saya akan beralih sudut di sini, apa kasus penggunaan untuk pernyataan coba bersarang yang cukup kuat untuk potensi efek samping yang telah saya uraikan? Bagaimana kode Go hari ini mendapatkan manfaat dengan mengizinkan pesta kurung yang dapat dipisahkan dengan sarang yang dapat disarang untuk muncul secara liar di mana saja? Dugaan saya adalah tidak dan saya tidak berpikir ada yang meminta untuk mencoba bersarang, itu datang dengan proposal karena diimplementasikan sebagai suatu fungsi. Anda tidak ingin menambahkan batasan apa pun seperti menghapus nesting/dapat dialamatkan untuk membatasi penyalahgunaan nesting atau kesalahan halus karena itu akan membuat spesifikasi bahasa lebih kompleks. Apakah tema di sini untuk mencegah pengenalan kompleksitas pada bahasa, atau untuk menambahkan cara yang lebih baik untuk menangani kesalahan?

Karena jika tujuannya di sini adalah untuk tidak membuat spesifikasi bahasa lebih kompleks, pilihannya jelas: Jangan menambahkan fungsi baru dengan pengembalian & parameter generik, dapat disarangkan secara sewenang-wenang, menyediakan aliran kontrol dan mengubah aritas nilai yang diberikan ( tetapi hanya jika mereka memenuhi antarmuka bawaan tertentu) dan mungkin lebih dari yang saya lupakan misalnya fungsi dengan kompleksitas yang belum pernah terjadi sebelumnya. Jika tujuannya adalah untuk meningkatkan penanganan kesalahan, saya pikir itu harus dilakukan tanpa memperkenalkan cara baru untuk menghasilkan kesalahan.

@sirkon Saya telah melihat contoh itu beberapa kali sekarang. Saya setuju bahwa itu menarik. Tapi mari kita pikirkan lebih jauh. try builtin yang diusulkan pada dasarnya adalah gula sintaksis untuk jenis boilerplate tertentu yang ditemukan dalam kode Go. Jadi kita bisa mengonversi contoh itu ke kode aslinya.

    f, err := os.Open(fileName)
    if err != nil {
        return err
    }
    info, err := f.Stat()
    if err != nil {
        return err
    }

Kode itu memiliki bug yang sama. Saya pasti pernah melihat kode seperti itu. Tidak jelas bagi saya bahwa try bawaan membuat bug itu lebih mudah ditulis atau lebih sulit dilihat.

Jelas bagi saya aliran tradisional "lebih lambat" menyisakan lebih banyak ruang untuk melihat file harus ditutup dan try ini memicu kebocoran semacam ini karena orang cenderung lebih memilih pintasan daripada jalan panjang.

@godcong Fungsi catch() (atau serupa) hanya akan memungkinkan Anda untuk mendapatkan kesalahan, bukan untuk mengaturnya (dan biasanya seseorang ingin mengatur kesalahan dari fungsi terlampir dalam fungsi yang ditangguhkan yang beroperasi sebagai penangan kesalahan) . Itu bisa dibuat bekerja dengan membuat catch() mengembalikan *error yang merupakan alamat dari nilai pengembalian kesalahan fungsi terlampir. Tetapi mengapa tidak menggunakan nama hasil kesalahan saja daripada menambahkan mekanisme baru ke bahasa? Lihat juga proposal try yang membahas hal ini.

Juga, lihat PS di atas .

Sistem tipe Go macet di tahun 60-an dan dengan demikian secara alami tidak dapat menangani kasus tepi dengan baik. Jika Anda cukup berpandangan jauh untuk meminjam ide tahun 80-an, Anda akan memiliki metode untuk mengontrol aliran rawan kesalahan yang halus. Anda sedang mencoba membangun bangunan kaca dan logam di desa abad pertengahan sekarang: buruknya desa abad pertengahan ini tidak memiliki listrik dan pipa air sehingga Anda tidak akan memilikinya juga.

Akan menarik untuk melihat sejauh mana fasilitas err yang baru dan lebih baik akan digunakan di golang/go itu sendiri. Jika sama sekali.

Menarik juga untuk melihat apakah go2 fmt akan memiliki opsi untuk menampilkan go1.x .

Dari pengalaman saya sendiri, sejak saya menambahkan konteks dalam kesalahan yang saya kembalikan dengan:

import "github.com/pkg/errors"
func caller(arg string) error {
  val, err := callee(arg)
  if err != nil {
    return errors.Warpf(err, "failed to do something with %s", arg)
  }

  err = anotherCallee(val)
  if err != nil {
    return errors.Warpf(err, "failed to do something with %s", val)
  }

  return nil
}

tim pendukung jarang membutuhkan masukan saya untuk masalah yang muncul dalam produksi.

IMHO, saya percaya meningkatkan penanganan kesalahan bukan tentang mengurangi kode boilerplate tetapi memberikan cara yang lebih nyaman untuk menambahkan konteks ke kesalahan. Saya masih tidak dapat menemukan cara masuk akal yang baik untuk menggunakan try().

Mungkin tambahkan konteks dalam penundaan:

func caller(arg string) (err error) {
  defer func() {
    switch t := err.(type) {
      case CalleeErr:
        err = errors.Wrapf(err, "failed to do something with %s", arg)
      case AnotherCalleeErr:
        err = errors.Wrapf(err, "failed to do something with %s", val)
    }
  }()

  val := try(callee(arg))
  try(anotherCallee(val)
  return nil
}

Tampaknya tidak menghemat banyak pengetikan, tetapi kami mengorbankan keterbacaan dan kinerja.

Mungkin akhirnya menggunakan try() dengan cara ini:

func caller(arg string) error {
    val, err := callee(arg)
    try(errors.Warpf(err, "failed to do something with %s", arg))

    err = anotherCallee(val)
    try(errors.Warpf(err, "failed to do something with %s", val))

    return nil
  }

Itu mengurangi beberapa baris, itu saja.

bagi saya, sebagian besar solusi untuk masalah ini tampaknya mematahkan satu hal yang saya pikir terpisah dari bahasa lain yang menggunakan pengecualian: mekanisme penanganan kesalahan tidak digunakan sebagai aliran kontrol. Sebagian besar solusi ini menambahkan beberapa bentuk aliran kontrol (periksa/tangani, coba, tangkap, harapkan) di mana saya pikir tim Go mungkin juga menambahkan pengecualian dan menyebutnya sehari.

Meskipun saya akan senang jika kita dapat memiliki kasus khusus if dan return yang agak menyerupai ruby

return err if err != nil

PS Maafkan pengalaman saya dalam desain Bahasa, jika saya mengatakan sesuatu yang bodoh, jangan ragu untuk menunjukkannya dan mendidik saya.

bagaimana kalau menambahkan fungsi catch() di defer to catch jika percobaan ditemukan beberapa kesalahan seperti memulihkan().
contoh:

func doSomthing()(err error){
    //return error
}

func main(){
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

    try doSomthing()
}

pada banyak fungsi

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

   try{
  file1 := open("file1")
  defer file1.Close()
  file2 := open("file2")
  defer file2.Close()
   }
   //without try
    file3,err := open("file3")
    defer file3.Close()
 }

Bagaimana ini membantu menangani setiap kesalahan dengan cara yang terpisah?

seperti pengguna lain berkomitmen

func Foo() (err error) {
    defer func(){
        if err:=catch();err!=nil{
            //found error
        }
    }()

  file1 :=try open("file1")
  defer file1.Close()
  file2 :=try open("file2")
  defer file2.Close()

        //without try
       file3,err := open("file3")
       defer file3.Close()
 }

Dalam contoh Anda, Anda menangani semua kesalahan dengan penangguhan yang sama. Apa yang terjadi jika Anda ingin menambahkan pesan khusus dan informasi khusus ke kesalahan?

@ianlancetaylor Adakah yang menyarankan untuk menambah operator ":=" untuk mendukung "pengembalian yang disimpulkan" - Pada dasarnya berperilaku persis seperti coba tanpa pemanggilan fungsi. Ini akan menyelesaikan banyak masalah yang saya lihat di kedua sisi:

  • try sebagai nama untuk fitur tersebut telah diperdebatkan, selama kami menerapkan ini sebagai fungsi, kami terjebak memberikan nama yang saya tidak yakin siapa pun akan merasa 100% baik tentangnya.
  • try melakukan sejumlah hal yang belum pernah terjadi sebelumnya, ia memiliki input seperti append() dan memengaruhi aliran kontrol seperti panic() sambil menggantikan pola di mana-mana ( if err != nil ) .
  • try bersarang adalah konsekuensi dari keputusan untuk mengimplementasikannya sebagai sebuah fungsi, bukan sebagai nilai tambah yang berasal dari perdebatan teknis yang ketat.
  • try diimplementasikan sebagai fungsi untuk menjaga kompatibilitas ke belakang

Saya pikir jika kita hanya menyimpulkan pengembalian seperti yang kita lakukan, semuanya terlihat ringkas dan terasa lebih "Pergi" seperti:

f, err := os.Open(filename)
if err != nil {
   return ..., err
}
defer f.Close()

info, err := f.Stat()
if err != nil {
   return ..., err
}

_Masukkan deskripsi ilmu komputer yang benar untuk perilaku ini di sini_, hingga saat itu puas dengan pengembalian yang disimpulkan melalui Deklarasi variabel pendek :

f := os.Open(filename)
defer f.Close()
info := f.Stat()

Yang terlihat jauh lebih rapi daripada:

f := try(os.Open(filename))
defer f.Close()
info := try(f.Stat())

Ini menyelesaikan semua masalah yang saya sebutkan di atas sementara (menurut saya) merasa sedikit lebih "suka" dan mempertahankan kompatibilitas ke belakang. Tampaknya sedikit lebih mudah untuk dijelaskan juga, pengembalian "implisit" pada panggilan fungsi untuk try() terasa sangat tidak pada tempatnya mengingat arti try di mana-mana dalam setiap bahasa lain. Saya tidak dapat berbicara 100% untuk implementasi tetapi sepertinya itu berpotensi dilakukan dengan upaya yang kira-kira sama? AssignStmt dapat memiliki bidang yang ditambahkan yang menentukan ekspresi mana pada LHS yang menghilangkan nilai errnya untuk menginformasikan kompilasi backend yang sama sebagai builtin?

Saya suka pemeriksaan kesalahan apa adanya, tetapi jika ini benar-benar masalah yang harus diselesaikan, saya pikir kata kunci baru mungkin merupakan solusi yang lebih baik. Solusi apa pun kemungkinan akan melibatkan perubahan aliran kontrol, dan yang terbaik adalah membuatnya sejelas mungkin.

Dalam contoh ini, kondisi on dievaluasi setiap kali err disetel.

func example() (foo int, err error) {
    on err != nil {
        return foo, err
    }

    foo, err = calcThis()
    foo, err = calcThat(foo)

    return
}

Ini berfungsi tanpa mendeklarasikan nama untuk nilai yang dikembalikan dalam tanda tangan fungsi, juga.

func example() (*int, error) {
    var err error

    on err != nil {
        return nil, err
    }

    foo, err = calcThis()
    foo, err = calcThat(&foo)

    return &foo, nil
}

Ini juga dapat diatur beberapa kali. Berikut adalah contoh yang dibuat-buat:

func example() (*int, error) {
    var err error

    on err != nil {
        return nil, err
    }

    foo, err = calcThis()

    on err != nil {
        return &foo, err
    }

    foo, err = calcThat(&foo)

    return
}

Di mata saya, ini mempertahankan gaya dan keterbacaan Go, sambil memperjelas apa yang terjadi di setiap langkah (setelah Anda memahami paradigmanya), karena ini secara efektif memasukkan kondisi itu setelah setiap kemunculan err ditetapkan.

Anda bahkan dapat melakukan hal berikut:

func example() (foo int, err error) {
    var message string

    on err != nil {
        return foo, errors.Wrap(err, message)
    }

    message = "failed to calc this"
    foo, err = calcThis()

    message = "failed to calc that"
    foo, err = calcThat(foo)

    return
}

Akhirnya, ini memiliki penerapan di luar penanganan kesalahan. Ingin kembali jika foo == 0? Contoh lain yang dibuat-buat:

func example(i int) bool {
    on x == 0 {
        return false
    }

    x = calcSomeInt(i)
    return true
}

@cstockton

Saya akan memprotes bahwa akan terlalu mudah untuk menghindari kesalahan seperti itu, tetapi:

  • Ini sudah menjadi "gotcha" dengan fungsi yang mengembalikan _only_ error, seperti json.Unmarshal . Peninjau kode IME yang baik belajar untuk melihat ini dengan cukup cepat.
  • Itu masih merupakan kesalahan sintaksis dalam fungsi yang tidak mengembalikan nilai kesalahan, seperti metode http.Handler .
  • Jika Anda tahu bagaimana menangani kesalahan, Anda akan memikirkannya, Anda akan mengantisipasinya, dan Anda mungkin akan tetap menangkap nilai kesalahan _sehingga_ Anda bisa mengatasinya.
  • Jika niat Anda adalah untuk hanya meneruskan kesalahan yang ditemui untuk menjadikannya masalah orang lain (penelepon), ini menyelesaikannya, dengan kerugian kecil bahwa Anda kehilangan kesempatan untuk secara eksplisit menempelkan lebih banyak anotasi untuk konteks.

Jadi, setelah menimbang semua pro yang bisa saya pikirkan, dan gagal untuk melihat kerugian yang jelas, saya... di pagar. Saya menduga ada kerugian yang tidak jelas yang belum saya pertimbangkan. Tapi saya mulai menyukai ke mana arahnya, betapapun kecil nilainya bagi siapa pun.

Saya harap ini adalah cara yang tepat untuk merespons dan saya tidak melakukan a
kesalahan serius.

Pada 7/1/19, Chris Stockton [email protected] menulis:

@ianlancetaylor Adakah yang menyarankan untuk menambah operator ":=" untuk mendukung
"pengembalian yang disimpulkan" - Pada dasarnya berperilaku persis seperti coba tanpa fungsi
panggilan. [ ... ]

Apa yang saya temukan menarik dalam kasus ini adalah bahwa kita memiliki sesuatu
analog dengan paradigma "koma OK", di mana sekarang menghilangkan "err"
penerima tugas diizinkan dalam beberapa keadaan yang ditentukan dengan baik. Bernilai
mencatat, tetapi jelas tidak dengan sendirinya cukup untuk menjadikan ini sah
dalil.

Lucio.

Bug ini sudah mungkin, coba atau tidak - Go tidak mencegah Anda menulis kode yang buruk. Atau membalikkan ini, menggunakan kode buruk sebagai alasan mengapa try tidak boleh diizinkan bukanlah argumen yang meyakinkan. Sebaliknya, dokter hewan harus menandai kasus yang bermasalah.

@griesemer saya tidak setuju. Meskipun dapat menghemat penekanan tombol, aritmatika pointer dikecualikan dari Go dengan alasan memudahkan penulisan kode yang buruk dan rusak. Saya merasa bahwa ini adalah jenis fitur yang sama yang akan membuat bug lebih sulit dideteksi.

data := try(ioutil.ReadAll(try(os.Open("foo.txt"))))

Contoh tipikal dengan try menggunakan contoh seperti di atas, yang bagi saya jelas membocorkan deskriptor file. (Fakta bahwa Go memburu dan menutup deskriptor seperti itu di runtime tanpa sepengetahuan pengguna dalam implementasi saat ini adalah sesuatu yang mungkin memberi kami kenyamanan, tetapi bagaimanapun juga ada contoh yang lebih baik).

data := try(ioutil.ReadAll(try(http.Get("http://example.com/")).Body))

Di atas dibaca seperti kode yang benar, tetapi mengabaikan persyaratan bahwa badan respons dibaca secara penuh dan kemudian ditutup pada jalur bahagia. Jika Anda melihatnya cukup lama, keanggunan menjijikkan dari contoh yang salah akan membuat jelas bahwa kita akan melihat jenis bug ini di masa depan.

Sebagai seseorang yang mengulas lebih dari sekadar menulis kode pada saat ini, saya lebih suka Go tidak menambahkan fitur yang membuat kesalahan begitu menggoda.

@jesse-amano Menggunakan operator penugasan sebenarnya mencegah kasus ini menjadi mungkin, tanpa pernyataan penugasan eksplisit, di bawah ini berperilaku persis seperti yang mereka lakukan hari ini, yaitu:

json.Unmarshal(...)
(http.Handler)(h).ServeHTTP(w, r)

Adapun Nilai yang hanya mengembalikan kesalahan memenuhi syarat untuk dikembalikan seperti return json.Unmarshal(...) dan juga dapat direpresentasikan dalam bentuk yang lebih ringkas karena tidak perlu ada nilai di luar blok if.

if err := json.Unmarshal(...); err != nIl {
    return err
} 

Apa yang saya temukan menarik dalam kasus ini adalah bahwa kita memiliki sesuatu yang analog dengan paradigma "koma OK", di mana sekarang menghilangkan penerima hak "err" diizinkan dalam beberapa keadaan yang ditentukan dengan baik. Patut dicatat, tetapi jelas itu sendiri tidak cukup untuk menjadikan ini proposisi yang valid.

Perilaku akan identik dengan mencoba tanpa parens atau bersarang & berantai sewenang-wenang. Saya pikir akan sulit menemukan sesuatu yang menurut sebagian besar orang terasa alami tanpa melanggar bahasa. Saya akui karena tampaknya penulis Go cukup bertekad untuk menambahkan fitur jenis ini ke Go, saya benar-benar menggali lebih dalam untuk alternatif karena saya benar-benar yakin try dalam bentuknya saat ini tidak cocok untuk Go. Ini adalah hal terdekat yang dapat saya pikirkan yang tidak akan merusak SM, tetapi mungkin masih tidak terasa benar bagi cukup banyak orang. Either way saya berharap proposal percobaan ditolak atau seseorang datang dengan sesuatu yang lebih banyak orang bisa setujui.

edit: @jesse-amano Saya benar-benar melewatkan poin Anda, maaf! Saya kira berada di dalam fungsi yang tidak mengembalikan kesalahan akan menampilkan kesalahan kompilasi ketidakcocokan jumlah tugas yang khas? Saya membayangkan try mungkin akan memperkenalkan tipe baru dari pesan kesalahan kompiler untuk itu.

@beoran Mengenai https://github.com/golang/go/issues/32825#issuecomment -507126700 : Penanganan kesalahan sudah berbeda dari situasi ke situasi: Terkadang kami mengembalikan kesalahan tidak berubah, terkadang kami mengembalikan kesalahan yang didekorasi, terkadang kami bertindak atas kesalahan, dan terkadang kita (dapat dengan benar) mengabaikan kesalahan. Satu-satunya hal yang mereka semua bagikan (kecuali ketika kita mengabaikan kesalahan) adalah tes err != nil (yang sudah dapat kita lakukan dengan lebih dari satu cara). Sebanyak itu akan bagus untuk fitur bahasa baru untuk menangkap semua kasus ini (atau 95% dari mereka), konstruksi seperti itu sangat mungkin untuk mengganggu secara non-ortogonal dengan konstruksi kontrol lain yang sudah kita miliki. Artinya, yang terbaik yang bisa kita harapkan adalah membuat beberapa kasus ini (mungkin 20%, mungkin 50% dari mereka) lebih baik.

@cstockton Mengenai https://github.com/golang/go/issues/32825#issuecomment -507136111: Jika bersarang try adalah satu-satunya blok jalan yang tersisa dan go vet tidak cukup baik , Saya pikir kita dapat mempertimbangkan untuk melarang try bersarang - itu akan cukup mudah. Tetapi saat ini saya pikir kita masih dalam fase FUD (takut, tidak pasti, dan ragu), dengan hampir tidak ada orang yang benar-benar bereksperimen dengan try secara serius. Saya perhatikan bahwa orang-orang yang telah melakukannya, telah melaporkan secara positif.

PS: Masalah try terbuka lagi untuk umpan balik. Mari kita lanjutkan ke sana.

@cstockton Oh, tentu saja. Untuk memperjelas, poin yang saya tuju adalah bahwa _sudah_ praktik buruk untuk memanggil fungsi seperti json.Unmarshal tanpa menangkap nilai kesalahan di sebagian besar kasus, tetapi biasanya tidak dianggap praktik buruk untuk defer file.Close() sebagai gantinya dari defer func() { err = file.Close(); if err != nil { ... }; }() , dan kami belajar membedakannya dengan mudah. Jadi itu akan (mungkin) dengan perubahan yang Anda usulkan. Saya awalnya tersentak memikirkan seseorang dengan polos menggunakan foo := strconv.ParseFloat(bar, 64) ketika mereka bermaksud untuk menangani kesalahan, tetapi setelah pertimbangan singkat saya tidak benar-benar berpikir itu masalah.

@sirkon Mengenai https://github.com/golang/go/issues/32825#issuecomment -507167388 : Silakan tinggalkan pernyataan yang jelas tidak memenuhi syarat dari diskusi - mereka tidak memiliki tempat di sini. Sekadar catatan, banyak ide di Go sebenarnya dari tahun 80-an (paket, kompilasi terpisah, dll.) daripada tahun 60-an dan banyak yang jauh lebih muda (goroutine, antarmuka). Ide-ide ini mungkin masih tampak tua, tetapi mereka telah teruji oleh waktu (setidaknya sedikit waktu CS telah ada).

@turtleDev Mengenai https://github.com/golang/go/issues/32825#issuecomment -507231353: Go melakukan penanganan pengecualian, dan itu dilakukan dengan panic dan defer dan recover - kami hanya tidak menyebutnya "penanganan pengecualian" karena istilah itu memiliki konotasi yang menyesatkan untuk Go. Tetapi untuk memperjelas, Go dapat melakukan semua itu raise dengan try-catch dapat melakukan, dan banyak lagi (karena berbeda dengan try-catch , defer dapat digunakan bersyarat). Terima kasih.

@sorenvonsarvort Mengenai https://github.com/golang/go/issues/32825#issuecomment -507268293: Jika Anda ingin dekorasi kesalahan yang berbeda untuk setiap kasus, gunakan pernyataan if . Silakan lihat dokumen desain. Pertanyaan ini telah dijawab berkali-kali sekarang. Terima kasih.

@cstockton Mengenai https://github.com/golang/go/issues/32825#issuecomment -507306652: Ya, kami telah memikirkan mekanisme seperti itu. Secara khusus, kami telah memikirkan tentang "membalikkan tabel" dan alih-alih memberikan try , cukup berikan handle , yang mendeklarasikan penangan kesalahan. Jika ada handler (dan hanya saat itu), seseorang hanya akan meninggalkan err di LHS tugas, dan itu akan diperiksa secara implisit (seperti dengan try ). Itu memang terlihat bagus, tetapi juga sama sekali tidak terlihat, yang merupakan bendera merah besar. Kami ingin penanganan pengecualian terlihat secara eksplisit dalam kode, di setiap tempat. Tanpa itu, hampir tidak mungkin untuk membaca kode dan melihat di mana pemeriksaan kesalahan terjadi.

@griesemer terima kasih atas klarifikasinya. tetapi panik dan pulih memiliki kasus penggunaan yang berbeda dan sebagian besar sangat sulit ditemukan di basis kode produksi mana pun. yang membuat Anda hanya memiliki sedikit kendali atas konstruksi aliran. menambahkan konstruksi baru akan merusak konsistensi itu karena Anda sekarang memiliki kontrol baru dari konstruksi aliran yang melakukan sesuatu seperti pengembalian.

@matthew-noken Mengenai https://github.com/golang/go/issues/32825#issuecomment -507323973: Anda mengusulkan ide yang menarik; itu terlihat sangat mirip dengan mekanisme titik pengawasan debugger. Ada beberapa pertanyaan yang harus dijawab: Apakah blok on harus kembali (saya kira begitu, karena jika tidak, Anda masuk ke tanah kode spaghetti)? Bisakah seseorang memiliki lebih dari satu pernyataan on ? Seberapa rumit kondisi on (Ini harus dievaluasi pada setiap penugasan)? Perhatikan bahwa kita tidak dapat memiliki ekspresi arbitrer karena kita harus mengidentifikasi variabel secara unik dengan pernyataan on . Juga, sedikit kutukan di Go: Konstruk on menyiratkan kode tak terlihat untuk dieksekusi di tempat lain.

Jika Anda ingin mendalami hal ini lebih lanjut, saya sarankan untuk membahasnya di tempat lain (golang-nut, atau proposal baru yang berbeda). Terima kasih.

@as Mengenai https://github.com/golang/go/issues/32825#issuecomment -507345821:

aritmatika pointer dikeluarkan dari Go dengan premis bahwa itu memudahkan untuk menulis kode yang buruk dan rusak

Sebenarnya, itu dikecualikan karena akan membuat pengumpulan sampah menjadi sulit atau tidak mungkin (dan ya, seseorang juga dapat menulis kode yang tidak aman). Tetapi poin yang lebih penting di sini adalah bahwa ada bukti nyata dan pengalaman yang mendukung keputusan ini.

Belum ada pengalaman dan bukti bahwa try bersarang akan menjadi lazim atau umum. Tapi lihat https://github.com/golang/go/issues/32825#issuecomment -507358397.

@turtleDev Mengenai https://github.com/golang/go/issues/32825#issuecomment -507368167 : panic adalah _exactly_ pengecualian, dan recover di dalam fungsi yang ditangguhkan pada dasarnya adalah catch . Mereka mungkin lebih sulit ditemukan dalam kode produksi karena di Go kami tidak menyarankan Anda menulis kode Anda menggunakan pengecualian; mereka hanya boleh digunakan dalam keadaan luar biasa.

Mengenai jumlah struktur aliran kontrol: Usulannya sangat jelas bahwa try hanyalah gula sintaksis, tidak ada yang lain.

Saya sudah mencoba menjawab beberapa komentar terbaru di utas ini di utas ini. Tapi mari kita lanjutkan komentar baru pada proposal try dalam edisi try #32437 (sekarang dibuka kembali mulai hari ini); dan biarkan masalah ini dicadangkan untuk diskusi leave err != nil alone . Terima kasih.

@cstockton Komentar lain tentang https://github.com/golang/go/issues/32825#issuecomment -507306652 : Jika kami menerapkan ini, maka mulai dengan

    func f() int { ... }
    ...
    x := f()

dan berubah menjadi

    func f() (int, error) { ... }

akan berarti bahwa perilaku x := f() akan tiba-tiba dan diam-diam menjadi sangat berbeda.

Saya menjalankan beberapa eksperimen yang mirip dengan apa yang dilakukan @lpar di semua repositori go kami. Hasilnya ada di Intisari ini: https://Gist.github.com/freeformz/55abbe5da61a28ab94dbb662bfc7f763

@ianlancetaylor Saya benar-benar merasa ini akan bekerja dengan sangat baik dalam banyak kasus, dan membuat pelaporan kesalahan yang lebih baik tidak terlalu berdampak. Pertimbangkan contoh lengkap untuk dua kasus utama, pertama pemanggil mengembalikan kesalahan:

func f() int { ... }
func a() error {
    x := f() // if f() is updated to return an error, we get automatic error propagation by default
    ...
}

func b() {
    x := f() // if f() is updated to return an error, we get the same compiler error 
    // assignment mismatch: 1 variable but pkg.f returns 2 values
}

Saya pikir dalam kasus umum ini adalah manfaat yang bagus untuk pendekatan ini, kasus sudut di mana ini menciptakan masalah yang saya yakini sudah rapuh. Hanya satu yang bisa saya pikirkan yang bisa benar-benar jahat adalah menemui jalan buntu sebuah mutex:

func (t *T) a() error {
   t.mu.Lock()
   x := f() // if f() is updated to return an error, we get automatic error propagation by default
   if x > 15 {
     t.mu.Unlock()
     return errors.New("t > 15")
   }
   ...
}

Tapi saya pikir kode yang ditulis seperti itu sudah rentan terhadap kebuntuan jika bergantung pada panggilan perpustakaan asing untuk berhasil memiliki status program yang valid. Jika disimpan dalam ruang lingkup yang dapat hidup di luar kepanikan maka itu bisa menemui jalan buntu jika perpustakaan yang sama memperkenalkan kepanikan runtime melalui NPE. Selain itu, motivator utama untuk menulis kode seperti ini adalah biaya historis dari penangguhan hidup di tumpukan. Dengan peningkatan kinerja penangguhan tunggal yang hidup di tumpukan, kode seperti itu tidak terlalu diperlukan. Saya pikir setiap turunan dari jenis kesalahan ini mudah diperbaiki.

Akhirnya seperti argumen yang mendukung kekurangan "coba" dengan perkakas juga dapat diterapkan di sini. Mengingat peningkatan adopsi go-modul, kami memiliki peluang bagus untuk menyuntikkan langkah "library-upgrade linting" untuk menempatkan perubahan seperti itu di depan wajah pengguna dengan jelas.

@griesemer

Mengenai jumlah struktur aliran kontrol: Usulannya sangat jelas bahwa try hanyalah gula sintaksis, tidak ada yang lain.

Maaf, tapi try tidak akan menjadi makro (seperti C) jadi pada dasarnya, bagi pengguna akhir itu hanyalah kontrol lain dari pernyataan aliran.

Saya percaya saya tidak memiliki argumen objektif pada saat ini, jadi saya akan mengakui bahwa kita mungkin memerlukan penanganan kesalahan yang lebih baik, tetapi saya merasa try mungkin bukan solusi terbaik.

Sekali lagi, ini adalah pendapat saya dan saya hanya mewakili mereka. Saya yakin tim Go telah lebih memikirkan hal ini daripada yang pernah saya lakukan.

Sisi: Aneh bagi saya bahwa masalah ini memiliki 1335 suara positif sedangkan proposal try (#32437) hanya memiliki 279 suara mundur. Saya berharap orang-orang yang memilih ini untuk menolak proposal try sehingga perasaan komunitas tentangnya lebih jelas, karena kedua proposal ini saling eksklusif.

@griesemer

Penanganan kesalahan sudah berbeda dari situasi ke situasi: Terkadang kami mengembalikan kesalahan tidak berubah, terkadang kami mengembalikan kesalahan yang didekorasi, terkadang kami bertindak atas kesalahan, dan terkadang kami (dapat dengan benar) mengabaikan kesalahan.

Setuju di sana, itu sudah jelas.

Satu-satunya hal yang mereka semua bagikan (kecuali ketika kita mengabaikan kesalahan) adalah tes err != nil (yang sudah dapat kita lakukan dengan lebih dari satu cara). Sebanyak itu akan bagus untuk fitur bahasa baru untuk menangkap semua kasus ini (atau 95% dari mereka), konstruksi seperti itu sangat mungkin untuk mengganggu secara non-ortogonal dengan konstruksi kontrol lain yang sudah kita miliki. Artinya, yang terbaik yang bisa kita harapkan adalah membuat beberapa kasus ini (mungkin 20%, mungkin 50% dari mereka) lebih baik.

Pernyataan try() diusulkan juga "mengganggu" if dan return secara non-ortogonal, jadi saya akan mengatakan bahwa argumen itu tidak benar. Beberapa orang di sini tidak menyukai try() karena alasan itu, tetapi saya tidak setuju. Go bukan Oberon, sederhana tapi tidak minimalis, Go lebih praktis.

Di mana kami tidak setuju adalah bahwa ada baiknya untuk repot dengan konstruksi bahasa yang, seperti yang Anda akui sendiri, hanya memiliki penggunaan dan penerapan yang terbatas, dan itu sudah dapat dilakukan dengan benar dengan if dan return . Saya pikir banyak orang, seperti saya, yang mengacungkan jempol mereka ke utas ini sangat kecewa dengan try() sehingga mereka lebih suka tidak memilikinya sama sekali. Meskipun tidak ortogonal dengan pengembalian, try() yang lebih kuat dan lebih berguna secara umum mungkin adalah yang paling ingin dilihat oleh sebagian besar pemrogram Go.

@beoran ,

Anda menulis bahwa Anda ingin "lebih kuat", "lebih berguna secara umum" try() .

@griesemer menyebutkan 4 situasi:

  1. Kembalikan kesalahan tidak berubah
  2. Kembalikan kesalahan yang didekorasi
  3. Bertindak atas kesalahan
  4. Abaikan kesalahan

try() memecahkan 1 dengan desain: ini benar-benar jalan pintas untuk if err != nil { return ..., err } .

Konstruksi bahasa yang ada menyelesaikan 3 dan 4. Kita sudah dapat bertindak atas kesalahan dengan if err != nil { ... } dan akan sulit untuk menemukan struktur yang lebih ringkas dalam kasus itu. Kami sudah dapat mengabaikan kesalahan dengan _ .

Ini meninggalkan kita dengan 2 (mengembalikan kesalahan yang didekorasi). Proposal try() menyarankan untuk menggunakan pernyataan penangguhan untuk mendekorasi kesalahan, atau jika setiap kesalahan harus didekorasi secara berbeda maka gunakan konstruk if err != nil { ... } .

Alasannya dijelaskan dengan baik di bagian proposal ini :

Iterasi pertama proposal ini terinspirasi oleh dua ide dari Bagian Kunci Penanganan Kesalahan , yaitu menggunakan built-in daripada operator, dan fungsi Go biasa untuk menangani kesalahan daripada konstruksi bahasa pengendali kesalahan baru. Berbeda dengan posting itu, pengendali kesalahan kami memiliki tanda tangan fungsi tetap func(error) error untuk menyederhanakan masalah. Penangan kesalahan akan dipanggil oleh try jika ada kesalahan, tepat sebelum try dikembalikan dari fungsi terlampir. Berikut ini contohnya:

handler := func(err error) error {
        return fmt.Errorf("foo failed: %v", err)  // wrap error
}

f := try(os.Open(filename), handler)              // handler will be called in error case

Meskipun pendekatan ini mengizinkan spesifikasi penangan kesalahan yang ditentukan pengguna yang efisien, pendekatan ini juga membuka banyak pertanyaan yang tidak memiliki jawaban yang jelas benar: Apa yang harus terjadi jika penangan disediakan tetapi nihil? Haruskah try panik atau memperlakukannya sebagai penangan kesalahan yang tidak ada? Bagaimana jika pawang dipanggil dengan kesalahan non-nil dan kemudian mengembalikan hasil nihil? Apakah ini berarti kesalahannya "dibatalkan"? Atau haruskah fungsi terlampir kembali dengan kesalahan nihil? Juga tidak jelas apakah mengizinkan penangan kesalahan opsional akan membuat pemrogram mengabaikan penanganan kesalahan yang tepat sama sekali. Juga akan mudah untuk melakukan penanganan kesalahan yang tepat di mana-mana tetapi melewatkan satu kemunculan dari try . Dan seterusnya.

Iterasi berikutnya menghapus kemampuan untuk menyediakan penangan kesalahan yang ditentukan pengguna demi menggunakan defer untuk pembungkusan kesalahan. Ini tampaknya merupakan pendekatan yang lebih baik karena membuat penangan kesalahan lebih terlihat dalam kode. Langkah ini menghilangkan semua pertanyaan seputar fungsi opsional sebagai penangan kesalahan tetapi mengharuskan hasil kesalahan diberi nama jika akses ke sana diperlukan (kami memutuskan bahwa ini baik-baik saja).

[...]

Jika kita menentukan di jalan bahwa memiliki beberapa bentuk fungsi pengendali kesalahan yang disediakan secara eksplisit, atau parameter tambahan lainnya dalam hal ini, adalah ide yang bagus, sangat mungkin untuk meneruskan argumen tambahan itu ke panggilan coba.

Apakah Anda tidak setuju dengan alasan ini?

Saya tahu bagian proposal ini dan saya tidak setuju dengannya, karena fakta bahwa pertanyaan dibuka karena gagasan melewati penangan kesalahan, tidak berarti kita tidak memerlukan fitur seperti itu. Itu hanya berarti kita harus berpikir dengan baik untuk menjawab pertanyaan-pertanyaan itu dengan cara yang masuk akal.

Selanjutnya, sekarang, kami menangani semua 4 kasus penggunaan kesalahan dengan pernyataan if err != nil , yang dipahami secara luas, idiom Go yang konsisten. Hanya menggunakan try() untuk kasus 1, dan mungkin untuk kasus 2, jika kita tidak keberatan dengan overhead melakukan pembungkusan kesalahan dalam pernyataan penangguhan, berarti kode untuk penanganan kesalahan akan dipecah menjadi if dan try tidak konsisten, dan jika penanganan kesalahan berubah, kita harus beralih antara yang satu dan yang lain.

Versi yang lebih kuat dari try() , yang dapat digunakan dalam semua kasus akan memungkinkan kita untuk menggunakan try() hampir selalu, dan ini kemudian akan menjadi idiom penanganan kesalahan baru yang konsisten untuk Go.

Namun, dengan try() seperti sekarang, itu tidak cukup berlaku secara luas, dan tidak ada cukup kenyamanan yang diperoleh untuk memperkenalkan inkonsistensi yang disebutkan di atas dalam penanganan kesalahan ke dalam basis kode kami. Itu sebabnya saya merasa tidak puas dengan proposal try() , dan berpikir bahwa tidak melakukan apa-apa lebih baik.

@beoran Saya pikir kasus 1 dan 2 memiliki kesamaan untuk mengembalikan kesalahan dari fungsi (masing-masing tanpa dan dengan dekorasi), sedangkan kasus 3 dan 4 tidak (masing-masing bertindak atas kesalahan dan mengabaikan kesalahan). Saya pikir fokus 'coba ()' ada pada kasus 1 dan 2.

Bagaimana jika proposal try() dapat ditingkatkan untuk menangani kasus 1 dan 2, dengan menerima fungsi penangan opsional? Tentu saja, ini membutuhkan jawaban yang masuk akal untuk pertanyaan-pertanyaan yang tercantum dalam proposal, tetapi tampaknya penurut. Apakah Anda mendukung sesuatu seperti itu?

Di sini saya keluar. Jika kasusnya adalah kami ingin pengguna memeriksa kesalahan, kami mungkin harus menambahkan kesalahan yang diperiksa (seperti pengecualian yang diperiksa). Dengan begitu kami sejelas mungkin dan pengguna tahu bahwa mereka sedang memeriksa semua kesalahan.

Dalam semua keseriusan, jika saya adalah orang di balik pengambilan keputusan ini, saya benar-benar ingin menggunakan kembali operator Kotlin ? atau sesuatu seperti perilaku unwrap() rust.

Salah satu dari ini saya pikir akan menjadi peningkatan:

getFile()?.getPath()?.toString()

di mana Anda mendapatkan nil kembali jika ada kesalahan di sepanjang jalan atau

get_file().unwrap().get_path().unwrap().lossy_to_string()

di mana ia meledak di tengah jalan jika ada kesalahan. Rust menangani yang kedua dengan memiliki fungsi ekspresif match yang memungkinkan Anda melakukan pencarian kesalahan secara menyeluruh dan menangani masing-masing secara terpisah, semuanya mengembalikan nilai semacam rantai.

Pada 7/2/19, Nicolas Grilly [email protected] menulis:

@beoran Saya pikir kasus 1 dan 2 memiliki kesamaan untuk mengembalikan kesalahan dari
fungsi (masing-masing tanpa dan dengan dekorasi), sedangkan kasus 3 dan 4
jangan (masing-masing bertindak atas kesalahan dan mengabaikan kesalahan). Saya pikir 'coba()`
fokus pada kasus 1 dan 2.

Saya agak kecewa tidak melihat lebih banyak diskusi tentang saran saya
bahwa itu adalah bagian "pengembalian" dari "pengembalian kesalahan" yang perlu
ditangani, bukan bagian "kesalahan".

Kemudian lagi, mungkin saya harus mengikuti pendekatan yang lebih resmi. saya
hanya tidak pandai merumuskan proposal, saya cenderung pergi ke mana-mana
tempat.

Kasus 1 dan 2, menurut saya, lebih baik dilayani oleh perintah "gagal"
kata kunci yang dengan jelas menunjukkan (setelah terbiasa) a
perubahan dalam alur program dan yang tidak tunduk pada
tradisi yang tidak nyaman sehubungan dengan sintaksisnya yang lengkap.

Apa yang mengikuti dari itu, bagaimanapun, apakah kita suka atau tidak, adalah
posisi "err" sebagai parameter pengembalian terakhir akan segera
menjadi hukum daripada konvensi. Itu adalah salah satu dari banyak "tidak disengaja" atau
konsekuensi "jaminan" yang perlu dipertimbangkan.

Akan ada banyak konsekuensi lain seperti itu, dari minimal hingga
bencana, beberapa yang hanya mendukung secara oportunistik
usul. Saya pribadi akan berbuat salah di sisi hati-hati, saya lakukan
mengerti mengapa Tim Go dan Robert khususnya mencari
dukungan dan tidak diragukan lagi terluka bahwa perlawanan ternyata begitu
Bagus.

Ini bentrokan ideologi politik, mungkin kita perlu banyak menggali
lebih dalam untuk mencari akar sebenarnya yang membutuhkan perhatian berkebun.

@lootch Apakah Anda memiliki masalah khusus dengan kesalahan yang perlu menjadi parameter pengembalian terakhir agar try berfungsi? Bukankah itu sudah menjadi konvensi de-facto?

(Sebagai tambahan, kami tidak "terluka" tentang perlawanan - kebanyakan terperangah tentang reaksi yang terlalu besar.)

@griesemer maaf atas analogi mobil tua tetapi proposalnya terasa seperti "Kami telah memutuskan untuk menambahkan sistem bahan bakar diesel ke semua mobil bensin, atau baterai dan motor listrik ke semua mobil bensin." Penanganan kesalahan Go cukup baik. Saya khawatir nilai tambah akan lebih kecil daripada biayanya, termasuk footgun baru dan mental overhead.

Saya hanya ingin menulis komentar singkat yang mengatakan bahwa setelah menulis banyak Go (saya telah menggunakan Go sejak rilis publik pertamanya pada tahun 2009 -- lihat github saya) saya akan menyambut baik peningkatan ergonomi seputar penanganan kesalahan. Sementara keeksplisitan penanganan kesalahan Go bagus, itu juga menyebalkan dalam kode sekuensial. Kurangnya introspeksi dan mengetik di sekitar nilai-nilai aktual itu sendiri (yang sedang dibahas dalam proposal yang berbeda) tidak dalam pengalaman saya benar-benar meningkatkan ketahanan program.

Saya cukup kesal pada ini beberapa tahun yang lalu saya benar-benar menulis gula di sekitar kepanikan dan pulih untuk memungkinkan mereka bekerja (kebanyakan) seperti pengecualian yang tidak dicentang: https://hackthology.com/exceptions-for-go-as-a-library. html . Sebenarnya menggunakan pembungkus itu adalah ide yang buruk karena komunitas berada. Namun, saya terus percaya bahwa meningkatkan ergonomi seputar penanganan kesalahan adalah sebuah kemenangan.

Tampaknya gila bahwa orang-orang dengan bersemangat berdebat untuk mempertahankan cara yang sangat bertele-tele tetapi tidak membantu untuk menyebarkan kondisi kesalahan. Saya telah menulis dan menemukan bug nyata dalam kode saya (dan kode lainnya) di mana orang telah mengacaukan kondisi if err != nil dan membuat bug. Benar-benar tidak ada alasan bagi bug itu untuk ditulis. Pemeriksaan statis dapat membantu tetapi tidak menghilangkan bug ini.

Saya mendukung proposal untuk meningkatkan ergonomi seputar penanganan kesalahan.

Proses proposal adalah untuk, mengutip https://golang.org/s/proposal , "Mengusulkan Perubahan untuk Dilanjutkan."
Masalah ini tidak mengusulkan perubahan, jadi sebenarnya ini sedikit kesalahan kategori.
Jika seseorang mengajukan proposal berjudul "biarkan pilih sendiri" kami hanya akan menutupnya sebagai bukan proposal.

Tapi sebenarnya masalah ini hanyalah perpanjangan dari diskusi masalah lain seperti #32437, jadi saya akan membiarkannya terbuka sebagai tempat yang baik untuk mendiskusikan "tidak melakukan apa-apa".

Saya telah menandainya Proposal-Tahan untuk menunjukkan bahwa tidak ada keputusan khusus di sini, lebih merupakan keputusan meta.

Sisi: Aneh bagi saya bahwa masalah ini memiliki 1335 suara positif sedangkan proposal try (#32437) memiliki _only_ 279 suara mundur.

Proposal percobaan dikunci pada saat saya menyadarinya, jadi saya tidak dapat menurunkannya. Saya berasumsi itu juga mengapa proposal ini dimasukkan untuk memulai.

Pada 7/2/19, Robert Griesemer [email protected] menulis:

@lootch Apakah Anda memiliki masalah khusus dengan kesalahan yang harus menjadi yang terakhir
kembalikan parameter agar try berfungsi? Bukankah itu sudah de-facto
Konvensi?

Saya melakukannya dalam arti bahwa jika itu menjadi "de facto" dilemparkan ke dalam batu, maka
pintu itu harus diayunkan terbuka dan membuat "kesalahan" opsional, khusus
jenis argumen dan terima itu, karena untuk setiap hasil yang benar ada
lebih sering daripada tidak banyak yang salah dan mereka mungkin juga
ditangani dengan cara khusus.

Begitu gagasan bahwa pernyataan "kembali" perlu diselidiki
lebih dalam (dan proposal percobaan tampaknya mengisyaratkan hal itu
arah), maka kondisi kesalahan tidak lagi "hanya nilai, dan
Pendekatan Go mulai menyerupai rumah kartu terbaik yang dibangun untuk
tanggal, tapi rumah kartu, bagaimanapun.

Saya adalah pengguna yang enggan dari beberapa trik pintar Go (saya punya
disebutkan di tempat lain bahwa x++ dan x-- tidak ditampilkan - kebanyakan, saya tergelincir
up kadang-kadang - dalam kode saya) jadi "coba" akan tetap menjadi salah satunya bagi saya,
tapi saya pada prinsipnya tidak keberatan dengan pengenalannya, saya hanya merasa
begitu banyak yang telah dikatakan, dan masih semua kemungkinan kerugian mungkin tidak
telah terungkap (konsekuensi yang tidak diinginkan dari apa yang saya lihat menjadi
keputusan politik akhirnya). Menguji itu mungkin bagus
atau buruk.

Apa yang saya lihat adalah bahwa kepanikan/pemulihan mendapat rap yang buruk dan ketidakadilan itu
akan kembali menghantui kita. Sekali lagi, saya belum menggunakan keduanya dan saya
takut hari saya harus karena saya bukan kue paling tajam di toples
dan saya akan merasa sangat sulit, tetapi jika panik/pulih didorong
untuk kesempatan langka di mana itu cocok (tidak ada yang diperlakukan oleh
Rob Pike dalam presentasinya yang luar biasa tentang kesalahan yang baru saja kembali
nilai, jika saya ingat dengan benar), itu akan jauh lebih jelas untuk semua itu
Go sudah menangani kesalahan serta dapat diharapkan tanpa perlu
untuk menjelajahi rawa pilihan yang mungkin tersedia di luarnya
batasan.

Yang mengatakan, masuk akal untuk mencoba, itu, setelah
semua, fitur opsional. Tapi satu efek sampingnya adalah apa ini
pertukaran adalah tentang: apa konsekuensi dari "de facto"
fungsi penanganan kesalahan yang menarik untuk memiliki argumen tipe "kesalahan"
di akhir daftar parameter pengembalian mereka? Bagaimana itu akan mengubah
persepsi bahwa "kesalahan hanyalah nilai"? Bagaimana itu akan cocok dengan
paradigma "koma-OK" yang sekarang jauh lebih analog? Apa lagi ini?
prinsip baru menimbulkan?

Yang terpenting, saya pikir gunung yang terbuat dari sarang tikus tanah ini adalah
menunjukkan bahwa Go telah mencapai tonggak sejarah yang mengubah hidup. Hampir
tentu, asumsi yang benar pada tahun 2013, mungkin tidak lagi
memegang. Bukannya itu berita bagi siapa pun, tetapi itu menunjukkan bahwa Go2 mungkin
tidak seindah yang kompatibel dengan Go1 seperti sebelumnya
terlalu tegas diusulkan (menurut saya).

@lootch Terima kasih atas tanggapan terperinci Anda. Memang sangat sulit untuk memperluas bahasa yang ada dengan cara yang kompatibel ke belakang, jadi saya setuju dengan Anda bahwa jika kompatibilitas ke belakang itu tidak diperlukan, mungkin seseorang mungkin melakukan hal-hal yang berbeda. Kami akan segera (setelah modul menjadi tempat umum) dapat membuat perubahan bahasa yang tidak memerlukan kompatibilitas mundur yang ketat.

Seperti yang Anda katakan, try adalah mekanisme opsional, dan - saya pikir itu layak diulang - terlepas dari semua kehebohan di sekitarnya, mekanisme yang sangat sederhana, mudah dijelaskan menggunakan fungsionalitas Go yang ada - hanya saja kita bisa' t tulis sendiri try sebagai fungsi di Go (dan obat generik juga tidak akan membantu, dalam hal ini). Jika kami bisa, saya yakin akan sangat umum melihat fungsi pembantu seperti try untuk penanganan kesalahan dalam kode yang ada. Bagaimanapun, apa yang Rob Pike bicarakan tentang kesalahan menjadi nilai adalah semua tentang: pemrograman dengan kesalahan.

Masih sangat mengejutkan bagi saya bahwa ada keributan mengenai penambahan fungsi pembantu yang cukup kecil sehingga semua orang bebas untuk mengabaikannya, namun orang-orang secara serius mempertimbangkan perubahan bahasa yang signifikan seperti on error yang benar-benar sangat menyarankan gaya tertentu penanganan kesalahan dalam bahasa.

Terima kasih sekali lagi atas masukan Anda. ini semua sangat menarik.

Saya tidak yakin apakah proposal ini adalah tempat yang tepat untuk membahasnya, tetapi mengingat sudah ada diskusi yang jelas tentang kata kunci try di utas ini, saya hanya akan mempertimbangkannya sesuai topik untuk saat ini :)

Saya ingin tahu apakah orang-orang Google bersedia menerapkan kata kunci try di repo Golang internal mereka, dan kemudian mengonversi basis kode Google yang ada untuk menggunakan kata kunci itu. Dengan menyimpannya secara internal saja, itu akan memungkinkan untuk mengembalikannya dengan mudah (yaitu, bebannya ada pada satu perusahaan, bukan seluruh komunitas).

Ini akan memungkinkan untuk melakukan studi kasus kecil tentang fitur ini dalam basis kode high-sloc dunia nyata. Facebook telah melakukan sesuatu yang mirip dengan fitur PHP di masa lalu, dan dengan cara itu mereka dapat menyempurnakan fungsionalitas tertentu sebelum mengusulkannya ke komunitas secara luas.

Jika Anda menulis studi kasus tentang bagaimana kata kunci try digunakan _dalam praktik_ dan nilai apa yang ditambahkannya dalam kehidupan nyata, itu bisa memberikan kasus yang menarik. Jika (secara hipotetis) tidak akan memberikan nilai dunia nyata, itu akan berharga untuk diketahui juga. Terkadang sesuatu terlihat sangat bagus di atas kertas tetapi tidak berhasil dalam praktiknya - atau sebaliknya.

@Freeaqingme Kami telah menghasilkan CL tentatif yang menunjukkan bagaimana try mungkin terlihat seperti di perpustakaan std: https://go-review.googlesource.com/c/go/+/182717 (mungkin ada kesalahan positif, tetapi jika ada, sangat jarang). Kami sedang mempertimbangkan mungkin mengembangkan alat yang memungkinkan konversi basis kode di kedua arah.

Anda juga dianjurkan untuk menggunakan tryhard dalam basis kode Anda dan melaporkan kembali.

Terima kasih.

@griesemer Saya mungkin tidak menjelaskan diri saya sendiri. Saya berasumsi Google menggunakan build Go mereka sendiri secara internal. Saran saya adalah menerapkan tambalan yang Anda tautkan di atas ke Google build internal, dan kemudian mengonversi (bagian dari) basis kode Google - bukan hanya stdlib, tetapi terutama proyek internal yang ditulis di Go. Jika insinyur Google menggunakannya selama beberapa bulan dalam situasi kehidupan nyata, itu akan memberikan wawasan yang baik tentang cara kerjanya dalam praktik.

Jelas saya dapat menerapkannya sendiri dan menggunakannya pada basis kode saya sendiri (dan saya mungkin juga). Tapi saya hanya pengembang tunggal dengan basis kode yang relatif kecil, jadi ini tidak akan mewakili jika banyak karyawan Google yang menggunakannya.

Secara pribadi saya masih ragu tentang fitur ini. Di satu sisi saya menghargai fakta bahwa itu dapat menyelamatkan saya beberapa penekanan tombol setiap kali. Tetapi kadang-kadang saya mungkin malas (bagaimanapun juga, saya manusia), dan hanya membuat pernyataan percobaan sebanyak mungkin. Sekarang saya hanya akan sedikit lebih disiplin, jika fitur ini ada. Tetapi bahkan jika saya, masih ada kemungkinan perpustakaan eksternal terlalu sering menggunakan/menyalahgunakan kata kunci ini sementara basis kode saya menderita karenanya (dalam hal kemampuan debug, perluasan perpustakaan tersebut).

@Freeaqingme Mengerti. Kita pasti bisa menjalankan try melalui repo internal. Saya tidak yakin kami dapat mengonversi dan mengonversi kembali - ada biaya signifikan yang terlibat di sini. Selain itu, kami hanya dapat melaporkan secara agregat (statistik) pada eksperimen ini karena kami tidak dapat melaporkan detail internal. Artinya, komunitas tidak akan memiliki cara mudah untuk memverifikasi klaim kami. Terakhir, basis kode Google mungkin tidak representatif.

Tapi terima kasih, poin diambil.

@griesemer Saya menghargai bahwa ini mungkin usaha yang mahal. Dalam hal ini saya tidak akan melakukannya. Jika ini hanya masalah penerapan proyek kerja keras Anda, maka biayanya bisa dibatasi. Tapi sebenarnya itu adalah sesuatu yang harus ditentukan oleh Googler (yang saya tidak).

Saya mengerti Anda tidak akan dapat melaporkan proyek Google individu atau infrastruktur internal. Namun, beberapa anekdot dapat dibagikan, mungkin. Tetapi apa yang menurut saya pribadi jauh lebih berharga adalah beberapa Googler yang melaporkan cara kerjanya bagi mereka. Tanpa membahas secara spesifik, pernyataan seperti "Saya mengharapkan X tetapi ketika saya mengalami kasus seperti A dan BI menemukan bahwa Y" menurut saya sangat berharga. Saya tidak perlu memverifikasi laporan semacam itu.

Terakhir, basis kode Google mungkin tidak representatif.

Bisa jadi, bisa jadi tidak. Tetapi ada banyak orang yang bekerja di Google, jadi saya rasa sebagian besar basis kode tidak didasarkan pada bagaimana satu individu memutuskan untuk menulisnya, melainkan menjadi puncak kontribusi dari banyak kontributor (karyawan) yang berbeda. Dalam hal itu, saya berharap segala sesuatunya menjadi representatif seperti yang bisa didapat. Mungkin tidak ada yang namanya basis kode representatif 100%.

Tetap seperti itu, sampai kami menemukan solusi yang lebih baik, try bukanlah yang kami cari. Tidak perlu mengambil tindakan bias dalam hal ini, luangkan waktu Anda Go Authors. Saya sangat yakin, sejauh saya berbicara dengan penjual di seluruh dunia setiap hari, bahwa mayoritas Komunitas Go tidak menerima atm proposal try .

Memperkenalkan sintaks baru berarti setiap orang harus meningkatkan versi Go mereka. Saya masih menggunakan Go 1.10 karena alur kerja saya didasarkan pada fakta bahwa saya dapat go get sesuatu dan kemudian menggunakannya dari baris perintah ( GOPATH saya ada di PATH ) . Baru-baru ini saya mengalami masalah ketika mencoba go get perpustakaan orang lain yang menggunakan modul. Saya mendapat kesalahan bahwa .../v2 tidak tersedia. Ini berarti sudah ada pemisahan kode (pikirkan Python 2 dan 3). Bagi saya ada dunia sebelum Go 1.11 dan setelah Go 1.11. Ini sangat mengganggu dan memperkenalkan sintaks baru untuk sesuatu yang berfungsi serta penanganan kesalahan di Go bukanlah pertukaran yang baik sama sekali. Ini memperkenalkan lebih banyak fragmentasi.

Pada 7/4/19, gonutz [email protected] menulis:

Memperkenalkan sintaks baru berarti setiap orang harus meningkatkan versi Go . mereka
Versi: kapan. Saya masih menggunakan Go 1.10 karena alur kerja saya berdasarkan fakta
bahwa saya dapat go get sesuatu dan kemudian menggunakannya dari baris perintah (my
GOPATH ada di PATH ). Saya baru-baru ini mengalami masalah saat mencoba go get
perpustakaan orang lain yang menggunakan modul. Saya mendapat kesalahan bahwa .../v2 adalah
tidak tersedia. Ini berarti sudah ada pemecahan kode (pikirkan
Python 2 dan 3). Bagi saya ada dunia sebelum Go 1.11 dan setelah Go 1.11.
Ini sangat menjengkelkan dan memperkenalkan sintaks baru untuk sesuatu yang berfungsi
serta penanganan kesalahan di Go bukanlah pertukaran yang baik sama sekali. Dia
memperkenalkan lebih banyak fragmentasi.

Jika itu penghiburan, saya berada di posisi yang persis sama vis-a-vis
Pergi modul. Saya belum menemukan waktu dan kesempatan untuk akrab
dengan mereka, jadi saya tetap menggunakan Go1.10 juga. Mungkin itu seharusnya
survei yang layak dimiliki.

Lucio.

--
Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung atau lihat di GitHub:
https://github.com/golang/go/issues/32825#issuecomment -508372318

--
Lucio De Re
2 Piet Retief St
Kestell (Negara Bebas Timur)
9860 Afrika Selatan

Telp.: +27 58 653 1433
Sel: +27 83 251 5824
FAKS: +27 58 653 1435

Saya seorang pengembang golang baru (masih belajar tentang go). Saya pikir penanganan kesalahan saat ini baik karena membuat kita mengelola kesalahan dengan mudah. Sebagai pengembang android, saya pikir try-catch lebih sulit untuk mengelola kesalahan kami daripada if err != nil{ } di golang. Dan saya pikir penanganan kesalahan eksplisit selalu lebih baik daripada penanganan kesalahan implisit.

PS. Maaf untuk bahasa saya.

leave it alone

Itu tidak rusak....

Suka meme, @Daniel1984 :-)

Kebetulan, proposal try meninggalkan if err != nil saja; itu hanya memberi Anda opsi tambahan yang masuk akal.

Saya berpendapat bahwa try tidak boleh dimasukkan. Pada penyertaan try :

Pro

  • Pemrogram mengurangi jumlah penekanan tombol yang mereka lakukan.
  • Pemrogram dapat memiliki singkatan untuk kembali dari fungsi saat ini la makro.
  • Ini tidak diperlukan.
  • Itu akan umum digunakan.
  • Jelas di mana keajaiban terjadi (tidak seperti Java throws ).
  • Mata tidak lagi berkaca-kaca saat melihat lautan cek nil .
  • Bekerja paling baik dengan implementasi sederhana.

Menipu

  • try menambahkan metode duplikat untuk operasi yang ada.
  • Untuk try untuk kembali dari fungsi saat ini tidak terduga, AKA lebih ajaib.
  • Ini menambah inkonsistensi pada pemeriksaan kesalahan.
  • Pemrogram tanpa pengalaman Go tidak akan mengerti.
  • Tidak mengubah penanganan kesalahan.
  • Kurang jelas (ketidakcocokan antara pengembalian fungsi dan nilai ekspresi).
  • Sulit untuk menggambarkan apa yang terjadi di try dengan kata-kata.

@griesemer itulah yang saya tidak suka. Hal-hal harus sederhana, saya tidak ingin menambah kompleksitas bahasa hanya untuk memiliki 2 cara untuk mencapai hal yang sama. Ada pola untuk menghindari verbositas if err != nil . https://www.ardanlabs.com/blog/2019/07/an-open-letter-to-the-go-team-about-try.html

Proposal Go2 #32437 menambahkan sintaks baru ke bahasa untuk membuat boilerplate if err != nil { return ... } tidak terlalu rumit.

Ada berbagai proposal alternatif: #32804 dan #32811 karena yang asli tidak disukai secara universal.

Untuk memasukkan alternatif lain ke dalam campuran: Mengapa tidak menyimpannya apa adanya ?

Saya mulai menyukai sifat eksplisit dari konstruksi if err != nil dan karena itu saya tidak mengerti mengapa kita membutuhkan sintaks baru untuk ini. Apakah itu benar-benar buruk?

Sangat banyak ini. Kode eksplisit adalah kode yang benar. Kengerian yang saya lihat dengan pengecualian penangan sudah cukup untuk pergi selamanya dari konstruksi yang tidak dapat dibaca yang mengerikan itu.

Tampaknya ada jeda besar, dengan orang-orang mulai berkomentar saja
sekarang dan orang tidak bisa tidak mendapatkan kesan bahwa itu segar
berita kepada mereka.

Itu perlu diperhitungkan juga. Grapevine jelas tidak seperti
cepat seperti yang mungkin dipikirkan.

Lucio.

Dan ubah gofmt untuk mengizinkan pernyataan satu baris if yang sederhana hand-ball dan kesalahan hingga
fungsi panggilan. Itu akan menghilangkan banyak kekacauan.

Dari pada:

err = fungsi saya()
jika salah != nihil {
kembali err
}

Mengizinkan:

err = fungsi saya()
if err != nil { kembalikan err}

Kebetulan, proposal percobaan tidak keluar jika err != nil saja; itu hanya memberi Anda opsi tambahan yang masuk akal.

Pembenaran yang tepat ini adalah bagaimana Go menjadi C++, C#, Scala, Kotlin, dll.

Sunting - ini mungkin menemukan cara yang salah. Saya tidak mengatakan bahwa try akan mengubah Go menjadi fitur bahasa yang membengkak. Saya mengatakan bahwa pembenaran di sini agak cacat

@deanveloper Anda memiliki contoh yang jelas tentang perilaku kesalahan pemahaman yang sulit dengan "coba":
https://github.com/golang/go/issues/32437#issuecomment -498932961

Bahkan jika itu sedikit berulang, saya setuju dengan OP.
Selain itu, imo semua alternatif yang diusulkan memperkenalkan kompleksitas yang tidak berguna.

Akan keren untuk menghilangkan tanda kurung kurawal ketika Anda hanya memiliki satu baris di dalam ruang lingkup

@tergila-gila

Ini berarti sudah ada pemisahan kode (pikirkan Python 2 dan 3). Bagi saya ada dunia sebelum Go 1.11 dan setelah Go 1.11.

Saya sudah lama menjadi programmer Python dan dugaan "perpecahan" yang Anda sebutkan tentang modul Go tidak seberapa dibandingkan dengan bencana migrasi dari Python 2 ke Python 3.

Ini sangat mengganggu dan memperkenalkan sintaks baru untuk sesuatu yang berfungsi serta penanganan kesalahan di Go bukanlah pertukaran yang baik sama sekali. Ini memperkenalkan lebih banyak fragmentasi.

try adalah fungsi bawaan dalam proposal. Ini sepenuhnya kompatibel ke belakang. Jika kode Anda sudah menggunakan try sebagai pengenal, pengenal Anda akan membayangi try bawaan.

@pongsatornw

Saya pikir penanganan kesalahan saat ini baik karena membuat kita mengelola kesalahan dengan mudah. Sebagai pengembang android, saya pikir try-catch lebih sulit untuk mengelola kesalahan kami daripada jika err != nil{ } di golang. Dan saya pikir penanganan kesalahan eksplisit selalu lebih baik daripada penanganan kesalahan implisit.

Sudahkah Anda membaca proposal secara lengkap? try hanyalah fungsi bawaan yang membantu memfaktorkan pengulangan if err != nil { return ..., err } . Logika umum penanganan kesalahan di Go tetap sama. Itu masih eksplisit, kesalahan masih nilai, dan tidak ada try-catch (alias pengecualian).

@kroppt

  • try menambahkan metode duplikat untuk operasi yang ada.

try hanyalah memfaktorkan kode berulang. Itu sama dengan append . Kita dapat menulisnya sendiri setiap kali kita menambahkan elemen ke sebuah irisan, tetapi lebih mudah untuk memanggil append .

  • Ini menambah inkonsistensi pada pemeriksaan kesalahan.

Anda dapat memanipulasi irisan "secara manual" menggunakan [...:...] atau Anda dapat menggunakan append , tergantung pada apa yang Anda lakukan. Tidak ada inkonsistensi. Mereka hanya alat yang berbeda untuk tugas yang berbeda. Sama untuk kesalahan, dengan if err != nil { ... } , atau dengan try , tergantung pada tugas yang ada.

  • Untuk try untuk kembali dari fungsi saat ini tidak terduga, AKA lebih ajaib.

Tidak terduga karena masih baru. Kami terbiasa dengannya karena kami lebih sering menggunakannya. Dan saya tidak berpikir itu sihir; spek try sangat mudah.

  • Pemrogram tanpa pengalaman Go tidak akan mengerti.
  • Sulit untuk menggambarkan apa yang terjadi di try dengan kata-kata.

Pemrogram tanpa pengalaman Go tidak akan mengerti chan , defer , 'go , iota , panic , restore , <- , type assertions, and many other things either without reading the documentation. try` mudah dibandingkan dengan kebanyakan dari ini.

  • Tidak mengubah penanganan kesalahan.

Mungkin itu hal yang baik, menurut penjual yang meminta untuk meninggalkan if err != nil sendirian ;-)

@marcopeereboom

Kode eksplisit adalah kode yang benar. Kengerian yang saya lihat dengan pengecualian penangan sudah cukup untuk pergi selamanya dari konstruksi yang tidak dapat dibaca yang mengerikan itu.

try sama sekali tidak ada hubungannya dengan penanganan pengecualian. Sudahkah Anda membaca proposal lengkapnya? Tidak ada yang sebanding dengan penanganan pengecualian seperti di Java atau Python misalnya. try eksplisit. Kesalahan harus disebutkan dalam tanda tangan fungsi. Kesalahan harus ditangani di situs panggilan. Tidak ada pelepasan tumpukan. Dll.

@gale93

Akan keren untuk menghilangkan tanda kurung kurawal ketika Anda hanya memiliki satu baris di dalam ruang lingkup

Saya pikir sebagian besar penjual memiliki pemikiran yang sama, dan saya membaca proposal serupa berkali-kali di pelacak masalah. Tapi ini adalah perubahan yang jauh lebih besar dari try . Tidak masuk akal untuk melakukan ini hanya untuk pernyataan if . Jadi, Anda harus mengubah ini di mana pun blok diterima. Tanpa { menandai awal blok, Anda harus menentukan cara untuk membatasi akhir ekspresi kondisional. Anda harus memperbarui tata bahasa, parser, gofmt, dll. Ini akan sepenuhnya mengubah permukaan bahasa.

@ngrilly
Moderasi dan menjaga bahasa tetap sederhana adalah penting.

Beberapa argumen yang Anda gunakan dapat membenarkan banyak perubahan pada spesifikasi. Tidak hanya poin positif di sini.

Saya mengevaluasi keputusan berdasarkan apakah itu akan membantu atau menyakiti, tidak harus sepenuhnya memberlakukan filosofi tertentu. Anda benar bahwa beberapa hal dalam spesifikasi melanggar prinsip-prinsip tertentu di mana go didirikan, tetapi ini semua tentang moderasi. Perubahan ini tidak memiliki dampak yang cukup positif bagi saya untuk mentolerir hal-hal negatif.

Hai @kroppt ,

menjaga bahasa tetap sederhana itu penting

Saya setuju dan saya pikir kita semua berjuang untuk ini.

Saya mengevaluasi keputusan berdasarkan apakah itu akan membantu atau menyakiti, tidak harus sepenuhnya memberlakukan filosofi tertentu.

Saya pikir kita semua mengevaluasi try berdasarkan manfaat dan biayanya. Diskusinya adalah tentang mendefinisikan dan menemukan konsensus berbasis fakta tentang manfaat dan biaya tersebut, yang saya coba lakukan dalam komentar saya sebelumnya.

Anda benar bahwa beberapa hal dalam spesifikasi melanggar prinsip-prinsip tertentu yang menjadi dasar go

Selama beberapa tahun terakhir, saya telah membaca hampir semua yang telah dipublikasikan oleh tim Go tentang Go dan desainnya, dan In tidak mengerti apa yang Anda maksud. Saya rasa proposal try melanggar prinsip dasar Go.

@ngrilly
https://talks.golang.org/2012/splash.article menjelaskan beberapa konsep di balik apa yang membuat go berbeda - kejelasan dan kesederhanaan, antara lain. Saya pikir ini adalah konflik yang sebagian dari kita lihat dengan perubahan baru ini. Ini lebih sederhana, tetapi kurang jelas. Bagi saya tampaknya keuntungan dalam kesederhanaan lebih kecil daripada hilangnya kejelasan. Mungkin saya salah dan saya hanya berhati-hati.

@kroppt Saya sudah membaca artikel ini puluhan kali ;-) Saya tidak setuju dengan gagasan bahwa try mengaburkan kode. try hanyalah fungsi bawaan yang digunakan untuk memfaktorkan beberapa kode berulang. Kami melakukan itu sepanjang waktu sebagai programmer. Ketika kami mengidentifikasi pola berulang, kami memfaktorkannya dalam fungsi baru. Jika tidak, kita akan memiliki satu fungsi main() yang panjang dengan semua kode kita di dalamnya.

@ngrilly
Apa yang Anda gambarkan ada di bagian "pro" saya:

  • Pemrogram mengurangi jumlah penekanan tombol yang mereka lakukan.
  • Pemrogram dapat memiliki singkatan untuk kembali dari fungsi saat ini la makro.
  • Mata tidak lagi berkaca-kaca saat melihat lautan cek nil .

Sekali lagi, saya tidak melihat gunanya menyebutkan penerapan universal suatu prinsip ketika kita tidak menerapkannya secara universal di sini.

Saya tidak setuju dengan gagasan bahwa try mengaburkan kode

Inti dari perubahan ini adalah untuk mengaburkan/menyembunyikan/menyederhanakan/mewakili kode - jika tidak, kita akan melihat blok pemeriksaan kesalahan asli. Pertanyaannya adalah apakah itu membuat kurang jelas artinya.

Saya pikir go awalnya mencapai keseimbangan kesederhanaan yang luar biasa, ke titik di mana ia berkontribusi daripada menghilangkan kejelasan. Saya tidak bisa menjelaskan bagaimana mereka melakukannya, tetapi try menurut saya tidak.

Saya tidak berpikir kita harus menganggap verbositas sebagai masalah. Kode perlu dibaca dan dipahami oleh manusia — yang waktunya lebih mahal daripada komputer — dan _pemahaman_ cenderung menjadi bagian yang sulit dan memakan waktu.

Saya menemukan bahwa struktur lekukan penanganan kesalahan go membantu saya mengikuti apa yang terjadi. Setiap pemeriksaan kesalahan bersifat eksplisit. Sebagian besar kesalahan yang tidak tertangani juga eksplisit. Ini membuat kode cepat dimengerti, bagi saya.

Saya juga berpikir bahwa meskipun cek if err != nil tampak membosankan, saya sebenarnya tidak perlu _type_ mereka. Saya hanya meminta editor saya melakukannya.

@kroppt

Inti dari perubahan ini adalah untuk mengaburkan/menyembunyikan/menyederhanakan/mewakili kode - jika tidak, kita akan melihat blok pemeriksaan kesalahan asli.

Tetapi Anda dapat menggunakan argumen ini untuk panggilan fungsi apa pun! Jika saya memanggil strings.HasPrefix("foobar", "foo") , apakah itu mengaburkan kode? Apakah Anda lebih suka menulis dan membaca l := len("foo"); len("foobar") >= l && s[0:l] == "foo" ?

@rossmcf

Setiap pemeriksaan kesalahan bersifat eksplisit.

coba masih secara eksplisit memeriksa kesalahan. Ini adalah raison d'être dari mencoba.

Saya juga berpikir bahwa jika pemeriksaan err != nil terlihat membosankan, saya tidak perlu mengetiknya.

Tidak membosankan untuk mengetik. Ini membosankan untuk membaca, ketika kita memiliki 3 baris yang sama di mana-mana. Ini adalah pengulangan, dan kami sebagai programmer biasanya cenderung untuk memfaktorkannya. Mungkin try memiliki kelemahan lain, tapi tidak yang ini menurut saya.

coba masih secara eksplisit memeriksa kesalahan
Perbedaan antara abstraksi try dan strings.HasPrefix adalah bahwa try secara implisit kembali.
Saat membaca kode go, saya tahu bahwa alur eksekusi tetap dalam fungsi saya sampai saya:

  • baca kurung tutup suatu fungsi tanpa tipe pengembalian
  • baca kata kunci return , panic
  • baca syscall.Exit(code)
    Dengan try , saya tidak dapat membaca kode dengan cara yang sama. Memindai garis secara visual dan melihat nol pernyataan "kembali" tidak lagi berarti "semua baris ini dijalankan, atau satu blok, atau program dihentikan."

@ngrilly Anda dapat membalas lebih dari satu orang dalam satu posting FYI, 10 balasan dalam beberapa jam dengan 5 berturut-turut pada satu titik membuat sulit untuk mengikuti diskusi. Setelah membaca posting Anda selain dari beberapa kesalahan, saya belum melihat argumen konkret baru yang terbentuk yang menjelaskan manfaat mencoba. Saya telah melihat satu manfaat: mencegah pengetikan if err != nil . Ini datang dengan biaya memperkenalkan cara-cara baru untuk membocorkan sumber daya , kemampuan untuk menulis kode yang kurang ringkas dan yang terburuk memungkinkan percobaan bersarang .

Saya merasa spesifikasi dan argumen yang dibentuk oleh para pendukung menyesatkan, saat ini hanya memberikan contoh kasus terbaik tanpa menunjukkan contoh kasus terburuk. Itu tidak mengevaluasi atau menyebutkan kelemahan negatif di atas atau faktor mitigasi potensial apa pun. Itu tidak membenarkan mengapa itu tidak membatasi penerapan percobaan untuk penggunaan yang diusulkan dan ditunjukkan. Alat tryhard digunakan untuk menampilkan kode yang lebih ringkas yang secara subyektif memberikan estetika yang lebih baik kepada beberapa orang, tanpa alat trytoohard yang menunjukkan kemampuan penuh dari apa yang dapat dilakukannya, mis. pernyataan. Akhirnya nama itu sendiri dikaitkan di mana-mana di dunia pemrograman dengan pengecualian, memungkinkannya untuk dapat bersarang dan terkait dengan kesalahan dan menempatkannya berdekatan sebagai bawaan untuk pemulihan dan kepanikan yang tidak terkait meninggalkan hal-hal yang terlihat tidak pada tempatnya. Saya percaya dan percaya pada kemampuan penulis Go untuk menghasilkan sesuatu yang lebih baik.

Ada terlalu banyak biaya di sini untuk dibenarkan dengan satu nilai tambah yang saya lihat dimuntahkan dalam balasan oleh para pendukung: "Saya tidak lagi harus mengetik if err != nil " - hal yang telah dengan sungguh-sungguh dipertahankan dan tertanam bersama dengan kesalahannya adalah nilai-nilai oleh seluruh komunitas Go. Kami telah mencapai satu dekade kode yang ditulis menggunakan if err != nil - yang beberapa kemajuan teknologi paling menonjol (docker, k8s, ...) pada saat yang sama semuanya digunakan dengan sukses besar.

Sebagai penutup if err != nil bukanlah beban untuk disembunyikan dengan builtin, tetapi sesuatu yang kita semua harus kenali sebagai bahan inti keberhasilan bahasa. Bahkan jika kita secara kolektif menerimanya sebagai beban, batasan untuk menghilangkannya harus tinggi dan tanpa kompromi. Saat ini terlalu banyak aspek coba yang merupakan kompromi.

Saya memiliki pendapat tentang metode mana yang lebih mudah tetapi itu adalah pendapat. Percobaan yang diberikan sederhana dan pemeriksaan eksplisit saat ini sederhana. Hebat kedua cara itu sederhana. Masalahnya bagi saya adalah itu meningkatkan beban kognitif pembaca dan penulis kode apa pun. Sekarang keduanya harus menafsirkan banyak cara untuk melakukan sesuatu. Dan penulis harus memilih cara mana untuk melakukan sesuatu dan/atau mengambil risiko melakukan sesuatu secara berbeda dari paket atau proyek lainnya yang sedang mereka kerjakan. Jika coba menggantikan pemeriksaan eksplisit yang masih akan meningkatkan beban kognitif karena pengembalian implisit sebagai hal lain untuk diuraikan.

_Mengesampingkan semua itu sejenak dan mengingat kita sekarang memiliki dua cara yang sama sederhananya untuk menangani kesalahan, kita masih memiliki masalah:_ Sederhana tidak lagi mudah . Dan itu membuka pintu untuk semua hal yang dirancang untuk dihindari.

Bilah untuk menambahkan sesuatu seperti ini harus jauh lebih tinggi, harus eksperimental untuk waktu yang lama untuk membuktikan bahwa lebih baik dengan data dari lapangan.

@cstockton

Anda dapat membalas lebih dari satu orang dalam satu posting FYI, 10 balasan dalam beberapa jam dengan 5 berturut-turut pada satu titik membuat sulit untuk mengikuti diskusi.

Ian telah menyarankan 7 hari yang lalu untuk memindahkan diskusi ini ke golang-nuts persis untuk alasan ini (tidak ada cara untuk membalas komentar tertentu, tidak ada threading), saran yang ditolak untuk memastikan diskusi akan "resmi". Kami memiliki apa yang kami minta.

@therealplato

Perbedaan antara abstraksi try dan strings.HasPrefix adalah bahwa try secara implisit kembali.

Itu benar. Saat membaca fungsi dan mencari titik "keluar", kita harus mencari return, panic, log.Panic, os.Exit, log.Fatal, dll... dan mencoba. Apakah itu masalah seperti itu? Jumlah titik keluar dalam suatu fungsi akan tetap sama dan akan tetap ditandai secara eksplisit, dengan atau tanpa try.

baca kata kunci kembali, panik

panik bukanlah kata kunci; itu adalah fungsi bawaan. Jika kita akan mengkritik proposal tim Go, yang mungkin lebih kompeten tentang desain bahasa daripada siapa pun di antara kita, maka setidaknya kita harus mendukung mereka untuk mendefinisikan sesuatu dengan benar. 😉

Saat membaca fungsi dan mencari titik "keluar", kita harus mencari return, panic, log.Panic, os.Exit, log.Fatal, dll... dan mencoba. Apakah itu masalah seperti itu?

Ini adalah masalah, karena try dapat muncul secara harfiah di mana pun ekspresi dapat muncul. Setiap titik keluar tunggal di Go dapat _only_ muncul sebagai pernyataan tunggal, try adalah satu-satunya hal yang dapat muncul sebagai ekspresi.

@ngrilly

Ian telah menyarankan 7 hari yang lalu untuk memindahkan diskusi ini ke golang-nuts persis untuk alasan ini (tidak ada cara untuk membalas komentar tertentu, tidak ada threading), saran yang ditolak untuk memastikan diskusi akan "resmi". Kami memiliki apa yang kami minta.

mulai pesan

@ pengguna1
jawab 1

@ pengguna2
jawab 2

akhiri pesan

Inilah yang dimaksud.

@cstockton

Saya telah melihat satu manfaat: mencegah pengetikan if err != nil.

try mencegah pengetikan berulang dan pembacaan if err != nil { return ..., err } (diformat pada 3 baris), bukan hanya if err != nil .

Ini datang dengan biaya memperkenalkan cara-cara baru untuk membocorkan sumber daya, kemampuan untuk menulis kode yang kurang ringkas dan yang terburuk memungkinkan percobaan bersarang.

Risiko kebocoran sumber daya yang Anda sebutkan dapat dicegah dengan vet dan lint .

Tentang "kode yang kurang ringkas", inti dari try adalah untuk menulis kode yang lebih ringkas, jadi saya tidak mengerti argumen Anda.

Risiko bersarang panggilan fungsi yang berlebihan tidak spesifik untuk try . Panggilan fungsi apa pun bisa terlalu bersarang. Ulasan kode dan linting akan membantu, seperti biasa.

Saya merasa spesifikasi dan argumen yang dibentuk oleh para pendukung menyesatkan, saat ini hanya memberikan contoh kasus terbaik tanpa menunjukkan contoh kasus terburuk.

Mungkin perasaan ini saling menguntungkan. Kita semua adalah penjual yang baik; jangan jatuh ke dalam penilaian nilai ;-)

Saya melihat dimuntahkan dalam balasan oleh pendukung: "Saya tidak lagi harus mengetik if err != nil"

Sekali lagi, saya tidak lagi harus mengetik l := len("foo"); len("foobar") >= l && s[0:l] == "foo" .
Saya dapat menggunakan strings.HasPrefix("foobar", "foo") sebagai gantinya.
Apa bedanya dengan try ?
Saya membaca sebelumnya Anda akan menerima "terbatas" try yang akan diberi nama check dan akan melarang bersarang.

Kami telah mencapai satu dekade kode yang ditulis menggunakan if err != nil - yang mana beberapa kemajuan teknologi paling menonjol (docker, k8s, ...) pada saat yang sama semuanya digunakan dengan sukses besar.

Kami juga memiliki banyak kode hebat yang ditulis dalam C, C++, Java, dll. Dengan alasan seperti ini, kami tidak akan memiliki Go.

Saat membaca diskusi tentang penanganan kesalahan di Go, saya tidak merasa semua orang berada di halaman yang sama mengenai proposal try , jadi saya memutuskan untuk menulis posting blog yang menunjukkan bagaimana try dapat digunakan: https://faiface.github.io/post/how-to-use-try/

Diskusi terkait di Reddit: https://www.reddit.com/r/golang/comments/c9eo3g/how_to_use_try_faiface_blog/

Saya tahu masalah ini bertentangan dengan try , tetapi saya harap posting saya dapat membawa beberapa perspektif baru :)

Go terjebak dan berjuang antara magis , atau logis untuk ide sederhana.

Kelebihan:

  • Kurangi boilerplate
  • Sederhana
  • Pola yang ada di antara bahasa lain
  • Opsional

Kontra:

  • Kurva Pembelajaran
  • sihir yang mendasari
  • Jenis bug baru
  • Go berpendirian, dan pragmatis dengan if != nil tetapi Anda dapat menggunakan try

Saya merasa seperti komunitas ini terutama. di sini berbeda dengan orang yang memilih di Go Survey [1] .
Pemilih mungkin tidak memilih ini sebagai perhatian utama melainkan meninggalkan untuk pertimbangan masa depan.
Namun hal itu dinilai berdampak karena penempatannya.

IMO, Menambahkan fitur bahasa sudah lama dan cara pemrograman modern menambahkan lebih banyak fitur pada editor yaitu Emmet atau cuplikan bahasa, pelipatan dan pewarnaan kode, pemfaktoran ulang dan pemformatan, debugging dan pengujian, menyarankan solusi untuk kesalahan dan mengutip dari godoc atau stack overflow , UI di atas kode sumber, dan biarkan kode sumber verbose
kode lipat if err != nil menjadi try

@ngrilly

coba cegah pengetikan dan pembacaan berulang if err != nil { return ..., err } (diformat pada 3 baris), bukan hanya if err != nil.

Apakah Anda percaya saya mengatakan "itu mencegah Anda mengetik jika err != nil" berarti saya benar-benar lupa bahwa kami juga membaca kode yang kami ketik?

Risiko kebocoran sumber daya yang Anda sebutkan dapat dicegah dengan dokter hewan dan serat kain.

Saya menautkan diskusi mengapa saya merasa dokter hewan dan kain bukan pilihan yang masuk akal di sini.

Tentang "kode yang kurang ringkas", inti dari percobaan adalah menulis kode yang lebih ringkas, jadi saya tidak mengerti argumen Anda.

Ya, apakah Anda membaca tautan yang "kemampuan untuk menulis kode yang kurang ringkas " sebenarnya menunjuk kepada Anda mungkin telah memahami argumen saya. _Perhatikan, meluangkan sedikit waktu untuk memahami argumen orang-orang yang Anda ajak berdiskusi adalah langkah pertama untuk menyajikan informasi yang mampu membuat mereka menyetujui pandangan Anda._

Risiko bersarang panggilan fungsi yang berlebihan tidak spesifik untuk dicoba. Panggilan fungsi apa pun bisa terlalu bersarang. Ulasan kode dan linting akan membantu, seperti biasa.

Menarik, mari kita uraikan ini:

1) Risiko bersarang panggilan fungsi yang berlebihan tidak spesifik untuk dicoba.

Ya, semua orang di sini mengerti bagaimana fungsi bekerja.

2) Panggilan fungsi apa pun bisa terlalu bersarang.

Ya, semua orang di sini mengerti bagaimana fungsi bekerja.

3) Ulasan kode dan linting akan membantu, seperti biasa.

Ya, Anda sudah membuat argumen lint dan "argumen ulasan kode" adalah kontrol bahasa luar lain yang dibuat dalam posting yang saya tautkan kepada Anda .

Mungkin perasaan ini saling menguntungkan. Kita semua adalah penjual yang baik; jangan jatuh ke dalam penilaian nilai ;-)

Saya tidak mengerti? Proposal tidak memiliki contoh kemampuan penuh yang disediakan implementasi, hanya penggunaan yang dimaksudkan. Alat tryhard yang digunakan untuk membantu mengukur pengaruh proposal menggunakan try dalam bentuk yang paling terbatas dan masuk akal, ini adalah fakta sederhana.

Sekali lagi, saya tidak lagi harus mengetik l := len("foo"); len("foobar") >= l && s[0:l] == "foo".
Saya bisa menggunakan strings.HasPrefix("foobar", "foo") sebagai gantinya.
Apa bedanya dengan try?

Saya melakukan yang terbaik untuk mengekstraksi posisi dari setiap pandangan yang berlawanan, jika tidak, saya tidak dapat membentuk argumen untuk membongkarnya. Saya benar-benar tidak bisa melihatnya di sini, maafkan saya. Saya akan menafsirkan ini satu-satunya cara saya dapat memahaminya: secara harfiah.

Apa bedanya ( strings.HasPrefix ) dengan try ?

string.HasPrefix

func HasPrefix

func HasPrefix(s, prefix string) bool

HasPrefix menguji apakah string s dimulai dengan awalan.

mencoba

func try adalah built-in seperti fungsi baru yang disebut try dengan signature (pseudo-code)

func try(expr) (T1, T2, … Tn)

di mana expr adalah singkatan dari ekspresi argumen masuk (biasanya panggilan fungsi) yang menghasilkan n+1 nilai hasil tipe T1, T2, ... Tn, dan kesalahan untuk nilai terakhir. Jika expr mengevaluasi ke nilai tunggal (n adalah 0), nilai itu harus dari kesalahan tipe dan try tidak mengembalikan hasil. Memanggil try dengan ekspresi yang tidak menghasilkan nilai terakhir dari kesalahan tipe menyebabkan kesalahan waktu kompilasi.

Coba bawaan hanya dapat digunakan di dalam fungsi dengan setidaknya satu parameter hasil di mana hasil terakhir adalah kesalahan tipe. Memanggil try dalam konteks yang berbeda menyebabkan kesalahan waktu kompilasi.

Menjalankan try dengan pemanggilan fungsi f() seperti pada (pseudo-code)

x1, x2, … xn = try(f())

turns into the following (in-lined) code:

t1, … tn, te := f()  // t1, … tn, te are local (invisible) temporaries
if te != nil {
        err = te     // assign te to the error result parameter
        return       // return from enclosing function
}
x1, … xn = t1, … tn  // assignment only if there was no error

Dengan kata lain, jika nilai terakhir yang dihasilkan oleh "expr", dari kesalahan tipe, adalah nihil, coba cukup kembalikan nilai n pertama, dengan kesalahan nil akhir dihilangkan. Jika nilai terakhir yang dihasilkan oleh "expr" tidak nihil, variabel hasil kesalahan fungsi terlampir (disebut err dalam pseudo-code di atas, tetapi mungkin memiliki nama lain atau tidak disebutkan namanya) diatur ke nilai kesalahan non-nol dan fungsi terlampir kembali. Jika fungsi terlampir mendeklarasikan parameter hasil bernama lainnya, parameter hasil tersebut mempertahankan nilai apa pun yang mereka miliki. Jika fungsi mendeklarasikan parameter hasil lain yang tidak disebutkan namanya, mereka menganggap nilai nol yang sesuai (yang sama dengan mempertahankan nilai yang sudah mereka miliki).

Jika try kebetulan digunakan dalam beberapa penugasan seperti dalam ilustrasi ini, dan kesalahan non-nil terdeteksi, penugasan (ke variabel yang ditentukan pengguna) tidak dijalankan dan tidak ada variabel di sisi kiri dari penugasan diubah. Artinya, coba berperilaku seperti panggilan fungsi: hasilnya hanya tersedia jika coba kembali ke situs panggilan yang sebenarnya (sebagai lawan dari kembali dari fungsi terlampir). Akibatnya, jika variabel di sisi kiri diberi nama parameter hasil, menggunakan try akan menghasilkan hasil yang berbeda dari kode biasa yang ditemukan saat ini. Misalnya, jika a, b, dan err semuanya bernama parameter hasil dari fungsi terlampir, kode ini

a, b, err = f()
if err != nil {
        return
}

akan selalu menyetel a, b, dan err, terlepas dari apakah f() mengembalikan kesalahan atau tidak. Sebaliknya

a, b = try(f())

akan meninggalkan a dan b tidak berubah jika terjadi kesalahan. Meskipun ini adalah perbedaan yang halus, kami yakin kasus seperti ini jarang terjadi. Jika perilaku saat ini diharapkan, pertahankan pernyataan if.

Mereka berbeda karena seluruh teks yang ditemukan dalam deskripsi try tidak ada dalam strings.HasPrefix. Pertanyaan yang lebih baik adalah bagaimana kesamaannya, yang akan saya jawab mereka berdua berbagi beberapa aspek Panggilan dan tidak ada yang lain.

Saya membaca sebelumnya Anda akan menerima percobaan "terbatas" yang akan diberi nama cek dan akan melarang bersarang.

Senang Anda membaca argumen utama saya yang menentang try: implementasinya tidak cukup membatasi. Saya percaya bahwa implementasinya harus cocok dengan semua contoh penggunaan proposal yang ringkas dan mudah dibaca.

_Atau_ proposal harus berisi contoh yang sesuai dengan implementasi sehingga semua orang yang mempertimbangkannya dapat mengetahui apa yang pasti akan muncul dalam kode Go. Seiring dengan semua kasus sudut yang mungkin kita hadapi saat memecahkan masalah yang kurang dari perangkat lunak yang ditulis secara ideal, yang terjadi dalam bahasa / lingkungan apa pun. Itu harus menjawab pertanyaan seperti apa jejak tumpukan akan terlihat dengan beberapa tingkat bersarang, apakah lokasi kesalahan mudah dikenali? Bagaimana dengan nilai metode, literal fungsi anonim? Jenis pelacakan tumpukan apa yang dihasilkan di bawah ini jika baris yang berisi panggilan ke fn() gagal?

fn := func(n int) (int, error) { ... }
return try(func() (int, error) { 
    mu.Lock()
    defer mu.Unlock()
    return try(try(fn(111111)) + try(fn(101010)) + try(func() (int, error) {
       // yea...
    })(2))
}(try(fn(1)))

Saya sangat menyadari akan ada banyak kode masuk akal yang ditulis, tetapi kami sekarang menyediakan alat yang belum pernah ada sebelumnya: kemampuan untuk berpotensi menulis kode tanpa aliran kontrol yang jelas. Jadi saya ingin membenarkan mengapa kami mengizinkannya sejak awal, saya tidak ingin waktu saya terbuang sia-sia untuk men-debug kode semacam ini. Karena saya tahu saya akan melakukannya, pengalaman telah mengajari saya bahwa seseorang akan melakukannya jika Anda mengizinkannya. Bahwa seseorang sering menjadi saya yang tidak tahu apa-apa.

Go menyediakan cara yang paling tidak mungkin bagi pengembang lain dan saya untuk saling membuang waktu dengan membatasi kami untuk menggunakan konstruksi biasa yang sama. Saya tidak ingin kehilangan itu tanpa manfaat yang luar biasa. Saya tidak percaya "karena coba diimplementasikan sebagai fungsi" menjadi manfaat yang luar biasa. Bisakah Anda memberikan alasan mengapa demikian?

Jangan buang waktu untuk masalah penanganan kesalahan ini, beri kami obat generik dan kami akan membuat sesuatu seperti Rust's Result.

Go terjebak dan berjuang antara magis , atau logis untuk ide sederhana.

Kelebihan:

  • Kurangi boilerplate
  • Sederhana
  • Pola yang ada di antara bahasa lain
  • Opsional

Kontra:

  • Kurva Pembelajaran
  • sihir yang mendasari
  • Jenis bug baru
  • Go berpendirian, dan pragmatis dengan if != nil tetapi Anda dapat menggunakan try

Saya merasa seperti komunitas ini terutama. di sini berbeda dengan orang yang memilih di Go Survey [1] .
Pemilih mungkin tidak memilih ini sebagai perhatian utama melainkan meninggalkan untuk pertimbangan masa depan.
Namun hal itu dinilai berdampak karena penempatannya.

IMO, Menambahkan fitur bahasa sudah lama dan cara pemrograman modern menambahkan lebih banyak fitur pada editor yaitu Emmet atau cuplikan bahasa, pelipatan dan pewarnaan kode, pemfaktoran ulang dan pemformatan, debugging dan pengujian, menyarankan solusi untuk kesalahan dan mengutip dari godoc atau stack overflow , UI di atas kode sumber, dan biarkan kode sumber verbose
kode lipat if err != nil menjadi try

Saya adalah orang yang memilih penanganan kesalahan yang lebih ketat tanpa kemungkinan lupa untuk memproses kesalahan. Bukan untuk dicoba.

Kami membutuhkan lebih dari sekadar obat generik untuk membuat ulang apa pun dari jarak jauh seperti tipe Result Rust. Bahkan _if_ tipe Result dapat dibuat hanya dengan obat generik, pemrogram pemula kemudian perlu mengetahui obat generik bahkan sebelum mereka dapat menangani kesalahan dengan benar, atau mengembalikan kesalahan dari fungsi "cara Result "

@deanveloper , maksud saya adalah: Saya memiliki lebih banyak manfaat dari obat generik daripada dari "perubahan sintaksis" dan saya yakin itu juga berlaku untuk komunitas.

@txgruppi Saya setuju bahwa obat generik harus memiliki prioritas yang lebih tinggi. Saya hanya mencoba mengatakan bahwa saya tidak berpikir bahwa obat generik akan menjadi pengganti yang baik untuk penanganan kesalahan.

@deanveloper , menurut saya masalah penanganan kesalahan ini hanya kosmetik, orang menghabiskan waktu mendiskusikan sesuatu yang stabil dan berfungsi dengan baik hanya karena Anda harus mengetik beberapa kode tambahan. Pelajari saja cara menulis kode yang lebih baik dan selesaikan ini dengan perubahan desain.
Sebelum seseorang mengatakan Generik sama mudahnya untuk diperbaiki dengan kode yang lebih baik: kompilasi kesalahan waktu ...

dapatkah itu diselesaikan dengan cuplikan atau makro keyboard? maka itu bukan masalah.

@txgruppi

Pelajari saja cara menulis kode yang lebih baik dan selesaikan ini dengan perubahan desain.

70% dari semua kode penanganan kesalahan di perpustakaan standar saat ini cocok untuk try seperti yang ditemukan Robert Griesemer fmt.HandleErrorf (belum ada). Saya harap Anda tidak ingin menyebut perpustakaan standar sebagai kode yang buruk.

dapatkah itu diselesaikan dengan cuplikan atau makro keyboard? maka itu bukan masalah.

Ini juga tentang membaca kode. Itu sebabnya kami tidak suka thing.Thing thing = new thing.Thing(thing.THING);

@faiface , apakah 'if err != nil' mulai mengembangkan perangkat lunak berkualitas? Saya tidak berpikir begitu.
Apakah kurangnya Generik menghalangi pengembangan perangkat lunak berkualitas? Ya itu.

Cara saya melihatnya adalah: Saya tidak memiliki cukup pengetahuan untuk mengimplementasikan obat generik jadi saya membutuhkan seseorang untuk mengimplementasikannya, tetapi penanganan kesalahan ini hanya membuang-buang waktu bagi pikiran yang dapat membuat obat generik menjadi kenyataan. Saya tidak menentang penanganan kesalahan ini karena ini adalah hal yang buruk, saya menentangnya karena ada hal yang lebih penting untuk diselesaikan.

@faiface perpustakaan standar bukanlah representasi yang baik dari kode Go yang sebenarnya. Ini karena perpustakaan standar lebih mungkin untuk melewatkan kesalahan tanpa menambahkan konteks, misalnya io/ioutil tidak pernah benar-benar perlu menghiasi kesalahan, itu hanya dapat melewatkan kesalahan yang terjadi di io . Robert Griesemer juga mengakui bahwa stdlib bukanlah representasi terbaik dari kode Go kehidupan nyata, namun saya menggunakan ponsel sekarang dan tidak ingin mencari komentar. Saya cukup yakin itu relatif dekat dengan posting tryhard aslinya.

@deanveloper @faiface Saat dijalankan melawan Go Corpus :

--- stats ---
 401679 (100.0% of  401679) func declarations
  97496 ( 24.3% of  401679) func declarations returning an error
 991348 (100.0% of  991348) statements
 217490 ( 21.9% of  991348) if statements
  88891 ( 40.9% of  217490) if <err> != nil statements
    485 (  0.5% of   88891) <err> name is different from "err" (-l flag lists details)
  59500 ( 66.9% of   88891) return ..., <err> blocks in if <err> != nil statements
  29391 ( 33.1% of   88891) complex error handler in if <err> != nil statements; cannot use try (-l flag lists details)
    596 (  0.7% of   88891) non-empty else blocks in if <err> != nil statements; cannot use try (-l flag lists details)
  52810 ( 59.4% of   88891) try candidates (-l flag lists details)

Jadi, dalam kode kehidupan nyata, 40% dari pernyataan if ditulis untuk pemeriksaan kesalahan, dan try dapat menghilangkan 59% dari mereka di luar kotak.

Saya setuju. Saya baik-baik saja dengan if err != nil. Sederhana dan bersih untuk fungsi yang mengembalikan nilai kesalahan tunggal. Saya juga menyukai paket kesalahan dan fungsi penyebab/bungkusnya ketika konteks kesalahan itu penting. Menggunakan kesalahan khusus dengan properti kode (sejauh yang saya tahu) mengharuskan Anda untuk melakukan pernyataan tipe atau menggunakan sesuatu sebagai pengganti antarmuka kesalahan standar sama sekali. Either way, saya tidak pernah menemukan diri saya membaca atau menulis kode Go dan merasa jengkel dengan cara penanganan kesalahan saat ini bekerja. Gangguan yang saya alami adalah kasus di mana banyak kesalahan dapat terjadi sebagai akibat dari pemrosesan kumpulan item. Namun, ini adalah masalah desain dan bukan masalah bahasa.

Perhatikan bahwa ketika saya mengatakan "ketika konteks kesalahan itu penting" saya mengacu pada situasi di mana mungkin terjadi gangguan jaringan dan jadi saya ingin mencoba lagi, atau mungkin hasil dari panggilan jenis "temukan" tidak memberikan hasil karena ada sebenarnya tidak ada, atau jari saya yang gelisah menambahkan 's' acak ke kueri SQL saya yang membuatnya meledak (ini sering terjadi pada saya ... Saya mungkin harus diperiksa untuk kerusakan saraf).

Pada 7/5/19, Nicolas Grilly [email protected] menulis:

@kroppt Saya sudah membaca puluhan kali ;-) Saya tidak setuju dengan gagasan bahwa try adalah
mengaburkan kode. coba hanyalah fungsi bawaan yang digunakan untuk memfaktorkan beberapa
kode berulang. Kami melakukan itu sepanjang waktu sebagai programmer. Ketika kita mengidentifikasi
pola berulang, kami memfaktorkannya dalam fungsi baru. Jika tidak, kami
akan memiliki satu fungsi main() yang panjang dengan semua kode kita di dalamnya.

Saya tergoda untuk menyebut Anda tidak jujur, tetapi saya menghormati karya Ian Lance Taylor
upaya manusia super untuk menjaga diskusi tetap sopan dan saya benar-benar tidak bisa
lihat apa yang akan diperoleh orang dengan sengaja berbohong di forum ini.

Yang mengatakan, "Ketika kami mengidentifikasi pola berulang, kami memasukkannya ke dalam
fungsi baru." Tentu, tetapi tidak dengan memberikan konstruksi yang saling bertentangan
bahwa, pada tahap akhir pengembangan Go ini, datang dengan dua
fitur tersembunyi: yang pertama adalah memperlakukan fungsi yang "kembali"
daftar argumen diakhiri dengan nilai error " sebagai spesial (atau yang lainnya
sebagai kesalahan semantik) dan yang kedua menyediakan aliran kontrol tersembunyi
jalan memutar yang analog tetapi tidak sepenuhnya identik dengan "kembali"
penyataan.

Jangankan lingkaran menyala yang menggunakan "menunda" memperkenalkan kesepakatan
dengan penggunaan yang lebih misterius dari "coba - fungsi semu". Seseorang
di tempat lain mengatakan, kira-kira "Saya tidak ingin menemukan try dalam kode
Saya membaca". Saya merasakan hal yang sama dan itu tidak boleh tersapu di bawah
karpet.

Saya telah menyatakan bahwa itu adalah aspek "pengembalian" dari "pengembalian kesalahan" yang
perlu ditangani, dan proposal "on err" paling mendekati
prinsip itu, tetapi juga agak membengkokkan aturan. Begitu juga milikku
saran "gagal" (menggerakkan argumen terakhir menjadi yang pertama, yaitu
membuatku tidak bahagia).

Lebih dalam lagi, tidak ada bahasa apa pun kecuali SNOBOL,
yang saya kenal telah, mengambil lompatan yang digambarkan Rob Pike sebagai
"kesalahan adalah nilai" sejauh yang dimiliki Go, tetapi ada sesuatu yang hilang
dalam proses: kesalahan "kondisi" adalah "bukan" nilai. Berhasil
penyelesaian suatu fungsi adalah kasus khusus dan begitu juga setiap kemungkinan
kegagalan.

Masing-masing (dan itu berlaku untuk penyelesaian yang berhasil, yang mungkin ada
lebih dari satu, juga) perlu diperlakukan berdasarkan kemampuannya, tetapi kami
bersikeras bahwa fungsi yang dipanggil harus memberi tahu kami pendapatnya tentang
kualitas penyelesaian dalam bentuk yang disingkat, sesuatu yang memiliki
telah dilakukan selamanya dan Rob telah terbukti menjadi kesalahpahaman.

Untuk mengilustrasikan poinnya, pertimbangkan nilai yang dikembalikan dari Pembaca:
io.EOF adalah kasus khusus yang terkadang sukses dan terkadang a
gagal, tetapi standar Go dengan bangga merupakan kesalahan ("io.Err != nil").
Apakah kita akan memiliki cara untuk menyingkatnya juga? Hampir pasti
tidak, karena kita sudah cukup terbiasa "memaafkan" "kesalahannya".

Saya telah lama menunggu keluarnya loop untuk menyampaikan "status" yang serupa atau
kode kondisi (pencarian dapat berakhir dengan nilai yang ditemukan atau kegagalan, bagaimana
apakah Anda memberi tahu yang mana, jika Anda ingin melakukan hal yang berbeda? Anda menambahkan tes,
di mana pengetahuan sudah ada - masalah yang sama, berbeda
konteks).

Ini adalah peningkatan nyata untuk bahasa tradisional: mengurangi boiler
piring tidak masuk akal, sebagai perbandingan.

Dan, perbandingan dengan operator ternary sama-sama valid: if ?:
tidak diperbolehkan "jangan sampai disalahgunakan", maka mencoba tidak boleh,
baik, setidaknya atas dasar itu.

Terus terang, mencoba adalah lark. Itu membuat Go lebih menarik bagi yang salah
hadirin. Selain bahaya dalam melakukan itu - siapa yang menginginkan orang yang salah
untuk bergabung dengan komunitas kami? - ada masalah preseden dan masalah
dari konsekuensi yang tidak diinginkan. Saya akan mengatakan "membuangnya" dan mari kita terima itu
kami belum sampai pada titik di mana kompatibilitas ke belakang dapat
dilanggar, jadi penanganan kesalahan harus tetap verbose.

Kami mengalami kepanikan/pemulihan dan itu perlu dipromosikan dari tingkat ketiga
warga negara ke penolong yang bersedia, dengan semua penjelasannya
yang membuat pemula (dan saya, saya akui takut) lebih
percaya diri menggunakannya.

Konstruksi "tunda" dalam penanganan kesalahan (yang telah saya adopsi -
tanpa menyadari impornya di tempat lain - secara konsisten dalam menyelesaikan
Transaksi SQL: tx.Rollback/tx.Commit) telah menjadi wahyu bagi saya.
Mungkin ada lebih banyak prinsip yang dapat dipelajari "dalam" ruang lingkup
apa yang sudah ditawarkan Go: mari tetap berada di dalam kotak itu untuk saat ini.

Satu hal seperti itu, tanpa henti, adalah meneruskan ke pelaporan kesalahan
fungsi daftar "error.Methods" yang akan dijalankan di bawah konvensional
kondisi (io.EOF, sql.ErrNoRows), alih-alih melaporkan hasilnya
sebagai hitam-putih. Tapi saya tidak sekolah dalam hal-hal seperti itu, saran saya
terlalu naif, biarkan orang lain (Roger, apakah kamu mendengarkan?) memelihara yang serupa
ide hingga membuahkan hasil.

Lucio.

"Mengetik itu tidak membosankan. Membaca itu membosankan, ketika kita memiliki hal yang sama
3 baris di mana-mana. Itu pengulangan, dan kami sebagai programmer biasanya
cenderung untuk faktor ini. Mungkin mencoba memiliki kekurangan lain, tetapi tidak ini
satu saya pikir."

Sekali lagi, tidak jujur ​​atau minimal, merasionalisasi. Saya mengabulkan itu
tiga baris dibaca lebih banyak daripada yang tertulis, tetapi
rasa sakit Griesemer yang bertujuan untuk meringankan ada dalam tulisan bukan dalam bacaan

  • yang tidak diragukan lagi dia anggap sebagai konsekuensi yang menguntungkan.

Tapi "err != nil" adalah penanda yang sangat familiar dan ketika "membaca" - as
bertentangan dengan "mencari" menggunakan editor, pola itu mudah untuk
spot dan mudah untuk membatalkan. Memfaktorkannya tidak sama
liga sama sekali. Dan harganya salah.

"Kami sebagai programmer" cenderung memfaktorkan pola yang lebih kompleks terlebih dahulu,
walaupun jarang terjadi. Kita juga tahu bahwa "jika err != nil { return
err }" dikompilasi menjadi urutan instruksi yang sangat sederhana, jika
siapa pun yang tidak, biarkan mereka mengangkat tangan di sini. Bisakah satu sama?
yakin bahwa itu akan terjadi dengan "coba - fungsi"?

Lucio.

@lootch Hei

Kami memfaktorkan pola berulang sebagai programmer, itu benar sekali.

Banyak kode berulang yang memperlambat pembacaan, jadi saya juga tidak melihat bagaimana itu tidak jujur.

Argumen tandingan Anda untuk ini pada dasarnya adalah "ayolah, itu bukan masalah besar". Nah, bagi banyak orang memang demikian.

siapa yang ingin orang yang salah bergabung dengan komunitas kita?

Ini adalah penjaga gerbang yang sangat arogan. Juga, alat tryhard telah mengungkapkan bahwa try secara langsung dapat diterapkan di banyak basis kode Go saat ini. Ini dapat langsung diterapkan ke 70% kode penanganan kesalahan di perpustakaan standar. Dengan perubahan kode (untuk menggunakan dekorasi kesalahan menggunakan defer , dll), saya yakin ini akan berlaku untuk lebih dari 80% penanganan kesalahan di semua kode Go.

Setuju, saya melampaui batas, di sini. Saya minta maaf.

Saya kira beberapa dari kita menjadi panas di bawah kerah karena diskusi ini
sedang berputar-putar.

Pada 7/7/19, Michal trba [email protected] menulis:

@lootch Hei
cukup yakin itu bukan karena pernyataan yang Anda tandai itu cantik
wajar.

Kami memfaktorkan pola berulang sebagai programmer, itu mutlak
benar.

Banyak kode berulang yang memperlambat pembacaan, jadi saya tidak mengerti bagaimana itu
tidak jujur ​​juga.

Argumen tandingan Anda untuk ini pada dasarnya adalah "Ayolah, ini bukan seperti
masalah besar". Ya, bagi banyak orang memang demikian.

siapa yang ingin orang yang salah bergabung dengan komunitas kita?

Ini adalah penjaga gerbang yang sangat arogan. Juga, alat tryhard telah mengungkapkan bahwa
try secara langsung dapat diterapkan di banyak basis kode Go saat ini. Itu bisa
langsung diterapkan ke 70% dari kode penanganan kesalahan di perpustakaan standar. Dengan
perubahan kode (untuk menggunakan dekorasi kesalahan menggunakan defer , dll), saya percaya
itu akan berlaku untuk lebih dari 80% penanganan kesalahan di semua kode Go.

--
Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung atau lihat di GitHub:
https://github.com/golang/go/issues/32825#issuecomment-508971768

--
Lucio De Re
2 Piet Retief St
Kestell (Negara Bebas Timur)
9860 Afrika Selatan

Telp.: +27 58 653 1433
Sel: +27 83 251 5824
FAKS: +27 58 653 1435

@lootch Alat peraga untuk menjadi sadar diri! Saya bisa memahami rasa frustrasi melihat diskusi berputar-putar.

Saya juga melihatnya dengan cara yang sama dan saya di sisi lain.

Mungkin kedua belah pihak hanya gagal untuk memahami satu sama lain. Sudahkah Anda membaca posting blog saya yang berjudul Bagaimana cara menggunakan 'coba'? di mana saya mencoba untuk menunjukkan bagaimana menggunakan 'coba' akan terlihat seperti dalam praktik, melakukan yang terbaik untuk tetap tidak bias?

Pada 7/7/19, Michal trba [email protected] menulis:

[ ... ]
Mungkin kedua belah pihak hanya gagal memahami pihak lain. Apakah kamu
baca posting blog saya yang disebut Cara menggunakan 'mencoba'? di mana saya mencoba untuk
tunjukkan bagaimana menggunakan 'coba' akan terlihat seperti dalam praktik, melakukan yang terbaik untuk tetap
tidak bias?

Saya akui saya tidak melakukannya, saya berharap dengan sungguh-sungguh bahwa saya tidak perlu melakukannya :-)

Sudahkah Anda mempertimbangkan aspek yang menurut saya diangkat Stockton, di mana hanya
sisi atas percobaan ditampilkan dan dia meminta perut yang lembut
terungkap juga? Saya khawatir saya setuju dengannya dan - tidak bermaksud menyinggung -
bahwa blog Anda mungkin menderita kekurangan yang sama.

Jika tidak, tolong dorong saya, bahan bacaan yang baik memiliki tempat khusus
dalam hidup saya :-)

Lucio.

@lootch Saya melakukan yang terbaik untuk menunjukkan sebanyak mungkin aspek 'coba' (yaitu ketika itu berlaku dan ketika tidak) dalam jumlah kode yang singkat dan membuatnya tidak bias dan realistis semampu saya. Tapi tentu saja, jangan mengambil kata-kata saya untuk itu :)

Ini adalah komentar top-upvoted pada diskusi Reddit terkait :

Ini adalah contoh hipotetis tidak bias yang berguna. Terima kasih telah menambahkan sesuatu yang konstruktif ke percakapan yang bukan hanya "menyebalkan".

@lootch Saya melakukan yang terbaik untuk menunjukkan sebanyak mungkin aspek 'coba' (yaitu ketika itu berlaku dan ketika tidak) dalam jumlah kode yang singkat dan membuatnya tidak bias dan realistis semampu saya. Tapi tentu saja, jangan mengambil kata-kata saya untuk itu :)

Ini adalah komentar top-upvoted pada diskusi Reddit terkait :

Ini adalah contoh hipotetis tidak bias yang berguna. Terima kasih telah menambahkan sesuatu yang konstruktif ke percakapan yang bukan hanya "menyebalkan".

Berfungsi dengan jalur file sebagai argumen? Ini saja akan menjadi alasan mengapa kode ini tidak lulus ulasan saya. Bagaimana jika beberapa bidang tidak ada? Diurutkan ulang?

@sirkon Agar tidak terlalu panjang, contohnya disederhanakan, tentu saja. Perubahan yang diperlukan untuk memperbaiki masalah yang Anda ajukan tidak memengaruhi praktik penanganan kesalahan, itulah yang terpenting di sana.

Perubahan yang diperlukan untuk memperbaiki masalah yang Anda ajukan tidak memengaruhi praktik penanganan kesalahan

Karena kamu bilang begitu?

  1. Mulai dari judul blog Anda: itu harus disebut "bagaimana tidak menulis", karena, saya ulangi, menggunakan jalur file sebagai parameter adalah praktik yang sangat buruk dan, sejujurnya, seluruh kode di bawah ini juga.
  2. Apakah Anda menyadari ini?
    go resp := Respondent{ Name: name, Gender: try(parseField(s, &line, "gender")), OS: try(parseField(s, &line, "os")), Lang: try(parseField(s, &line, "lang")), }
    akan menghasilkan pesan kesalahan yang buruk? Harus ada pesan kesalahan bidang yang tidak terduga dan setidaknya pesan kesalahan bidang yang hilang. Diagnostik skrip Anda di bawah standar.

PS Lihat repo Anda. Apakah Anda menyadari Go adalah alat yang buruk untuk tugas-tugas Anda? Anda harus memahami dalam praktik aplikasi Go yang sebenarnya, yang pertama akan melihat log adalah insinyur operasi, bukan pengembang. Pesan kesalahan yang tepat dapat membantu mereka memecahkan masalah sendiri.

@sirkon Ayo, jangan lakukan flamewars.

Apakah Anda menyadari ini akan menghasilkan pesan kesalahan yang buruk?

Mereka sepenuhnya memadai untuk model. Formatnya diharapkan berisi semua bidang dan berurutan. Pesan kesalahan memberitahunya dengan sangat jelas.

Jika Anda ingin bersaing dengan kualitas kode, mengapa Anda tidak menulis ulang sesuai standar kualitas Anda? Jika Anda melakukannya, saya akan mencoba dan melakukan yang terbaik untuk menulis ulang kode Anda untuk menggunakan try .

PS Lihat repo Anda. Apakah Anda menyadari Go adalah alat yang buruk untuk tugas-tugas Anda?

Apakah Anda menyarankan yang lain untuk tugas saya? Saya telah menggunakan cukup banyak. Btw, ini agak di luar topik.

@faiface

Apakah Anda menyarankan yang lain untuk tugas saya? Saya telah menggunakan cukup banyak. Btw, ini agak di luar topik.

Karat? C++?

@sirkon

Karat? C++?

Di sana kita pergi. Saya telah menggunakan keduanya sebelum menyelesaikan dengan Go. Saya tidak pernah melihat ke belakang.

@sirkon Salah satu kelemahan besar dari try adalah tidak adanya dekorasi kesalahan. Pemrogram dalam hal ini menunjukkan kemungkinan aplikasi try , jadi tentu saja tidak akan ada banyak dekorasi kesalahan yang terjadi.

Juga, mendiskreditkan orang berdasarkan proyek yang telah mereka kerjakan sepenuhnya di luar topik dan tidak beralasan. Anda telah cukup kasar dengan beberapa komentar terakhir Anda, dan saya ingin Anda setidaknya menyadari hal itu.

@deanveloper Terima kasih atas komentarnya!

Omong-omong

Pemrogram dalam hal ini menunjukkan kemungkinan aplikasi percobaan, jadi tentu saja tidak akan ada banyak dekorasi kesalahan yang terjadi.

Jika Anda merujuk ke blog saya, sebenarnya ada cukup banyak dekorasi kesalahan yang terjadi, hanya saja cara yang tidak sama persis seperti yang dilakukan @sirkon . Berikut beberapa pesan error dari program yang menggunakan try :

parse respondnts.txt: open respondnts.txt: no such file or directory
parse respondents.txt: line 12: parse field gender: expected "gender:"
parse respondents.txt: line 9: expected empty line
parse respondents.txt: line 4: parse field lang: EOF

@faiface Kesalahan saya, saya seharusnya lebih spesifik. try mencegah dekorasi kesalahan ketika Anda menginginkan beberapa pesan kesalahan dalam fungsi yang sama. Dimungkinkan untuk melakukan ini dengan draf check/handle dan dengan proposal tandingan "named handler". Akan sangat berguna dalam contoh spesifik yang ditunjukkan (di mana Anda menggunakan try saat menginisialisasi struct) untuk dapat menambahkan hiasan di sekitar setiap pesan, tetapi sayangnya proposal percobaan membuatnya agak sulit dilakukan tanpa menulis fungsi Anda sendiri.

Periksa/tangani tidak akan banyak membantu dalam kasus spesifik Anda. Tetapi ide yang diusulkan dari catch dan kontraproposal lainnya untuk try akan mampu menangani kesalahan sebagai menambahkan dekorasi tambahan.

@deanveloper Yah, sebagian besar waktu Anda perlu menggunakan dekorasi yang sama untuk semua kesalahan dalam suatu fungsi karena sub-fungsi diharapkan memberikan konteksnya sendiri. Namun, ketika Anda harus mendekorasi sesuatu secara berbeda dalam satu fungsi, masih ada solusi mudah dengan coba:

..., err := functionThatCanFail(...)
try(errors.Wrapf(err, ...))

Atau cukup bagi fungsi besar menjadi beberapa fungsi kecil.

@faiface di mata saya pada saat itu orang harus menggunakan if err != nil , tapi saya rasa ini masalah preferensi.

Namun terkadang (seperti dalam kasus inisialisasi struct) bukanlah ide yang baik untuk membagi menjadi beberapa fungsi. Saya mendapatkan sedikit nitpicky meskipun saya kira.

Saya sebenarnya tidak super terhadap try , tapi saya juga bukan pendukung besar. Saya pikir ada solusi lain yang lebih baik di luar sana.

@deanveloper

Namun terkadang (seperti dalam kasus inisialisasi struct) bukanlah ide yang baik untuk membagi menjadi beberapa fungsi.

Benar, tetapi juga tidak perlu mendekorasinya secara berbeda, karena semua dekorasi khusus yang diperlukan berasal dari parseField .

Saya pikir ada solusi lain yang lebih baik di luar sana.

Itu sangat mungkin! Jika saya melihat solusi yang lebih baik, saya akan menjatuhkan try dalam satu menit :)

sebagian besar waktu Anda perlu menggunakan dekorasi yang sama untuk semua kesalahan dalam suatu fungsi karena sub-fungsi diharapkan memberikan konteksnya sendiri

@faiface Saya sangat tidak setuju dengan pernyataan ini. Setiap fungsi adalah sub-fungsi dari yang lain pada tumpukan panggilan. Ini berarti memiliki tanggung jawab yang sama dalam alur penanganan kesalahan (yaitu memberikan konteks kesalahan ke lingkup atas).

Bayangkan sebuah fungsi yang menambahkan dua potongan data ke satu file. Bagaimana Anda membedakan mana dari penambahan yang gagal jika Anda hampir tidak mengembalikan pernyataan 'tidak dapat menulis ke file'?

Kita semua adalah makhluk yang malas. Saya juga, saya lebih suka melakukan sesuatu sekali untuk semua jika saya bisa. Dan ya, ketika saya memulai petualangan saya dengan Go, saya menganggap penanganan kesalahan agak rumit. Setelah beberapa tahun berlatih, pandangan saya berubah 180 derajat. Saya percaya penanganan kesalahan saat ini di Go mempromosikan pemrograman yang bertanggung jawab dan desain yang baik. IMHO itu akan menjadi kegagalan besar untuk menambahkan mekanisme lain yang merusak pendekatan ini.

@mklimuk Bagian penting dari komentar saya adalah "sebagian besar waktu". Contoh yang Anda berikan mungkin paling baik ditangani oleh if err != nil . Seperti disebutkan berkali-kali, try tidak dirancang untuk menangani semua situasi, hanya yang paling umum.

Dan bukti menunjukkan bahwa ia melakukannya, karena 70% dari semua kode penanganan kesalahan di perpustakaan standar dapat menggunakan try luar kotak dan hal yang sama berlaku untuk 59% dari semua kode penanganan kesalahan di liar.

@faiface baik fakta bahwa try dapat menggantikan penanganan kesalahan eksplisit tidak berarti harus. Dalam kasus saya, mengembalikan kesalahan tanpa menambahkan konteks bukanlah 'situasi paling umum'. Kebalikannya :)

Orang-orang yang mendukung utas ini hanya khawatir bahwa pernyataan baru ini akan merusak seluruh upaya di balik desain Go yang asli (kesederhanaan, kejelasan, dll.) demi membuat kode Go tidak terlalu bertele-tele.

Tentu, tapi saya harap Anda mengerti bahwa try bukan untuk mengembalikan kesalahan tanpa konteks. Faktanya, kasus paling umum untuk menambahkan konteks (satu konteks per fungsi) sangat disederhanakan dengan try :

func doSomething() (err error) {
    defer fmt.HandleErrorf(&err, "doing something")

    x := try(oneThing())
    try(anotherThing(x))
    // ...
}

Hal yang perlu disadari adalah bahwa sebagian besar waktu, oneThing() dan anotherThing() akan mengembalikan konteks yang cukup dengan sendirinya, jadi membungkusnya dengan "doing something: ..." sudah cukup.

Sebagai catatan tambahan, saya pikir kita bisa menggunakan beberapa konvensi pada _who_ yang melakukan dekorasi. Di stdlib beberapa fungsi melakukan ini, ex copy: x to y atau serupa, saya pribadi telah menyerahkan dekorasi ke pemanggil, karena memiliki argumen.

Misalnya jika saya memiliki Copy() saya akan melakukan sesuatu seperti return errors.Wrap(err, "writing") dan pemanggil menggunakan Copy() akan membungkus dengan errors.Wrapf(err, "copying from %v to %v", src, dst) atau serupa.

Keduanya tidak bercampur dan cocok dengan baik, dan kadang-kadang dapat berakhir dengan string duplikat, apakah yang terbaik adalah mengatakan gaya stdlib adalah idiomatis? Saya tidak ingat mereka semua berperilaku seperti ini. Saya pikir itulah satu-satunya cara contoh @faiface akan cukup. Mungkin saya telah membalikkan masalahnya, bagi saya rasanya lebih bersih untuk melakukan lebih sedikit dan menyerahkan keputusan kepada penelepon, terutama "berjaga-jaga" mereka menghilangkan informasi kontekstual.

Saya pribadi telah menyerahkan dekorasi kepada penelepon, karena memiliki argumen.

Ya. Misalnya, pertimbangkan fungsi yang mem-parsing badan JSON dari permintaan HTTP, memeriksa header, dan sebagainya. Jika diberi makan JSON yang tidak valid secara sintaksis, tanggung jawabnya — yang bisa dilakukannya, sungguh — adalah melaporkan kembali kesalahannya. _caller_ mengetahui bagian mana dari API yang coba dipanggil, dan perlu menghias kesalahan yang sesuai sebelum pada gilirannya meneruskannya ke rantai atau mengeluarkan kesalahan HTTP.

Jika fungsi Anda benar-benar memperhitungkan kode tujuan umum yang dapat digunakan di banyak tempat, mereka tidak akan memiliki informasi yang diperlukan untuk menutupi kesalahan. Sebaliknya jika mereka memiliki semua konteks, mereka mungkin tidak benar-benar fungsi yang masuk akal sebagai fungsi mandiri, Anda hanya membuat fungsi untuk memecah kode dan membuatnya terlihat lebih terorganisir daripada yang sebenarnya.

@lpar Pikiran memberikan contoh spesifik ini?

Saya sudah memberikan contoh spesifik? Pertimbangkan apakah fungsi parseJSON Anda benar-benar mengetahui konteksnya dan mampu mendekorasi titik akhir API dan aliran aktivitas yang menjadi tujuan parsing body. Itu akan menunjukkan bahwa itu khusus untuk titik akhir itu, atau bahwa Anda meneruskan informasi hanya agar Anda dapat menggunakannya untuk membungkus kesalahan.

@lpar Oke, jadi itu contoh lain di mana if err != nil akan tetap digunakan. Atau Anda membagi logika Anda menjadi beberapa fungsi.

Tetapi pahami bahwa memberikan contoh di mana try tidak sesuai bukanlah argumen yang menentang try . try tidak dimaksudkan untuk menggantikan semua penanganan kesalahan, hanya kasus yang paling umum.

Screenshot 2019-07-07 at 6 30 42 PM

@abejide001 proposal try bukanlah "coba/tangkap" tradisional dari banyak bahasa lain, ini jauh lebih mirip dengan makro try! di Rust. Meme yang bagus tapi lol

Ups - diposting ke masalah yang salah. Pindah ke https://github.com/golang/go/issues/32437#issuecomment -509024693.

Saya baru-baru ini memposting proposal #32968 yang didasarkan pada ketidaksetujuan saya dengan kemampuan berbahaya untuk bersarang yang dimiliki makro try . Meskipun saya berharap itu tidak memiliki kekurangan yang serius, sebagai penulis saya bukan orang yang tepat untuk melihatnya. Jadi saya ingin meminta kubu _jangan mencoba_ saya (kamu :) untuk melihat, menilai dan mengomentarinya.


Kutipan:

  • _Makro check bukan satu baris: ini paling membantu di mana banyak yang berulang
    pemeriksaan menggunakan ekspresi yang sama harus dilakukan dalam jarak dekat._
  • _Versi implisitnya sudah dikompilasi di taman bermain._

Kendala desain (terpenuhi)

Ini adalah bawaan, tidak bersarang dalam satu baris, memungkinkan lebih banyak aliran daripada try dan tidak memiliki harapan tentang bentuk kode di dalamnya. Itu tidak mendorong pengembalian telanjang.

contoh penggunaan

// built-in 'check' macro signature: 
func check(Condition bool) {}

check(err != nil) // explicit catch: label.
{
    ucred, err := getUserCredentials(user)
    remote, err := connectToApi(remoteUri)
    err, session, usertoken := remote.Auth(user, ucred)
    udata, err := session.getCalendar(usertoken)

  catch:               // sad path
    ucred.Clear()      // cleanup passwords
    remote.Close()     // do not leak sockets
    return nil, 0, err // dress before leaving
}
// happy path

// implicit catch: label is above last statement
check(x < 4) 
  {
    x, y = transformA(x, z)
    y, z = transformB(x, y)
    x, y = transformC(y, z)
    break // if x was < 4 after any of above
  }

Semoga ini bisa membantu, Selamat menikmati!

Tetapi pahami bahwa memberikan contoh di mana try tidak sesuai bukanlah argumen yang menentang try . try tidak dimaksudkan untuk menggantikan semua penanganan kesalahan, hanya kasus yang paling umum.

Dan sesuai statistik yang saya posting sebelumnya , itu bukan kasus paling umum dalam kode saya. Kasus paling umum dalam kode saya adalah kesalahan yang dibungkus sebelum kembali. Jadi try hanya akan sesuai untuk persentase satu digit dari pengembalian kesalahan saya yang terbaik (*), itulah sebabnya saya pikir kami membutuhkan sesuatu yang lebih baik.

(*) Dan faktanya, saya cenderung berpikir bahwa contoh pengembalian err telanjang kemungkinan besar merupakan kesalahan yang harus diperbaiki.

Sangat setuju, biarkan "if err != nil" saja.

@abejide001 proposal try bukanlah "coba/tangkap" tradisional dari banyak bahasa lain, ini jauh lebih mirip dengan makro try! di Rust. Meme yang bagus tapi lol

Ini saja yang menjadi perhatian saya, Go sudah menjadi bahasa yang asing bagi pendatang baru, dan sekarang kita harus menjelaskan mengapa try memiliki logika yang dipesan lebih dahulu. FWIW, saya tidak berpikir mengatakan "Rust melakukannya" adalah alasan yang masuk akal untuk membenarkan menambahkan sesuatu ke dalam bahasa - itu tidak terkenal.

@ karena saya tidak mengatakan itu untuk membenarkan fitur tersebut, saya hanya mengatakannya untuk mengklarifikasi apa yang dilakukan fitur tersebut. Saya cukup di tengah dengan proposal try .

Bukannya ini membuat banyak perbedaan, tetapi ini juga merupakan fitur di Swift juga, meskipun dengan kata kunci, bukan makro.

Tampaknya ada beberapa kebingungan tentang apa yang sebenarnya coba coba dicapai. IMHO, masalahnya bukan menulis banyak jika blok yang memeriksa kesalahan. Anda menulisnya sekali dan Anda selesai. Masalahnya adalah membaca kode yang memiliki banyak blok tersebut. Kita lebih banyak membaca daripada menulis. Dan blok-blok ini mengaburkan kode yang sebenarnya karena mereka terkait dengannya. Lebih buruk lagi, sering kali mereka hampir persis sama, dengan hanya perbedaan string kecil di suatu tempat di dalam blok if itu.

Saya pribadi lebih suka cek lama - menangani draft, tapi ini setidaknya melakukan pekerjaan yang baik memisahkan kesalahan dan jalur bisnis. Dan kami akhirnya mungkin dapat memiliki konteks cakupan fungsi tunggal sebagai lawan untuk setiap panggilan, yang saat ini memiliki peluang bagus untuk mengulangi hal yang sama seperti kesalahan induk.

@icholy menulis:

Ada banyak umpan balik komunitas yang meminta penanganan kesalahan yang lebih efisien (dari survei tahunan). Tim Go sekarang menangani masalah itu.

Saya baru saja melihat survei di sini: https://blog.golang.org/survey2018-results

Rupanya pertanyaannya adalah: "Apa tantangan terbesar yang Anda hadapi secara pribadi saat menggunakan Go hari ini?" dengan kemungkinan jawaban "Penanganan kesalahan".

Saya benar-benar bertanya-tanya bagaimana berdasarkan pertanyaan + jawaban itu disimpulkan bahwa sintaks yang lebih singkat diperlukan. Saya mungkin juga menjawab 'penanganan kesalahan', tetapi tidak berarti saya ingin melihat sintaks lain. Jika saya memeriksa opsi ini dalam survei, saya akan berpikir lebih baik mengizinkan untuk membungkus kesalahan, memberi mereka jejak tumpukan, dll.

Saran saya adalah mundur dari semua proposal penanganan kesalahan (efektif apa yang disarankan @miekg ). Dan pertama-tama tentukan apa sebenarnya yang diinginkan masyarakat, dokumentasikan itu. Kemudian cari tahu mengapa itu yang mereka inginkan. Dan hanya setelah itu mulailah mencari cara untuk mencapainya.

Saya baru saja melalui proposal percobaan, tetapi kecuali saya melewatkan sesuatu, ia mengabaikan untuk mengatakan _mengapa_ itu sedang diusulkan, selain "untuk menghilangkan pernyataan boilerplate if [...}". Tetapi tidak disebutkan mengapa penghapusan boilerplate itu jika pernyataan diperlukan.

Saya pasti setuju dengan yang di atas. Mari kita lihat apakah perubahan nilai kesalahan baru membantu membantu menangani keluhan kesalahan yang dialami orang-orang dengan Go. Kemudian kita dapat melihat apakah sintaks yang lebih singkat diperlukan.

Orang-orang di sini menentang try karena mereka merasa bahwa semua kesalahan yang dikembalikan harus diberi keterangan. Kenyataannya adalah, dalam kumpulan kode saat ini (termasuk pustaka standar), persentase pemeriksaan kesalahan yang tinggi memiliki ~bare~ pengembalian kesalahan yang tidak beranotasi dan akan mendapat manfaat dari try . Keyakinan Anda tentang bagaimana kode HARUS tidak ada hubungannya dengan cara kode IS . Bebaskan saya dari dogma Anda.

@icholy Mengabaikan kesalahan menunjukkan bahwa pengembang tidak peduli dengan kesalahan itu. Kesalahan tidak signifikan atau diyakini oleh penelepon tidak mungkin. Jika itu masalahnya maka "coba" sama tidak ada gunanya, pemanggil tidak akan membungkus fungsi dalam "coba".

Saran saya adalah mundur dari semua proposal penanganan kesalahan (efektif apa yang disarankan @miekg ). Dan pertama-tama tentukan apa sebenarnya yang diinginkan masyarakat, dokumentasikan itu. Kemudian cari tahu mengapa itu yang mereka inginkan. Dan hanya setelah itu mulailah mencari cara untuk mencapainya.

Saya sangat setuju dengan ini. Saya melihat banyak ketidaksepakatan mendasar tentang fungsionalitas apa yang harus didukung oleh peningkatan apa pun pada penanganan kesalahan Go. Setiap bagian fungsi yang berbeda yang disebutkan orang memicu bikeshedding atas penamaan dan sintaksisnya, sehingga diskusi tidak ke mana-mana.

Saya ingin tahu lebih detail apa yang sebenarnya diinginkan oleh komunitas Go yang lebih luas dari fitur penanganan kesalahan baru yang diusulkan.

Saya telah mengumpulkan survei yang mencantumkan banyak fitur berbeda, bagian dari fungsi penanganan kesalahan yang saya lihat orang usulkan. Saya telah dengan hati-hati _menghilangkan_ setiap penamaan atau sintaks yang diusulkan, dan tentu saja mencoba membuat survei netral daripada mendukung pendapat saya sendiri.

Jika orang ingin berpartisipasi, ini tautannya, disingkat untuk berbagi:

https://forms.gle/gaCBgxKRE4RMCz7c7

Setiap orang yang berpartisipasi harus dapat melihat hasil ringkasan. Kemudian mungkin setelah kita memiliki gagasan yang lebih baik tentang apa yang sebenarnya diinginkan orang, kita akan dapat berdiskusi dengan cerdas tentang apakah proposal percobaan menyediakan hal-hal tersebut. (Dan kemudian mungkin membahas sintaks.)

@lane-c-wagner apakah Anda mencoba mengatakan bahwa mengembalikan kesalahan yang tidak beranotasi itu sama dengan tidak mengembalikannya sama sekali? edit: perbaiki komentar sebelumnya

@icholy Ah saya salah paham. Ketika Anda mengatakan "telanjang", saya pikir Anda bermaksud "_" mengabaikan kesalahan.

Proposal ini berpendapat bahwa tidak ada tindakan yang harus menjadi tindakan yang valid. Perubahan ini mempengaruhi semua pengguna bahasa karena mereka membaca kode. Oleh karena itu, survei yang mengidentifikasi hambatan terbesar masih perlu menanyakan kepada masyarakat apakah hambatan ini layak untuk diperbaiki. Proposal ini adalah evaluasi terdekat dari pertanyaan semacam itu.

Tolong berhenti mengatakan "bahwa semua orang bebas untuk mengabaikan" try . Kami membaca kode yang ditulis oleh orang lain.

@ tv42 Saya tidak tahu apakah Anda berbicara dengan saya di sini , tetapi saya juga telah mengatakannya, dan Anda ada benarnya. Bersalah seperti yang dituduhkan. Saya akan mencoba untuk lebih berhati-hati dengan generalisasi seperti itu. Terima kasih.

@griesemer survei Anda sangat kurang. Saya memilih penanganan kesalahan, tetapi masalah yang saya maksud adalah keamanan tipe penuh, bukan verbositas. Anda sebaiknya membuat satu lagi tentang kesalahan saja.

Dan saya masih ingin tipe jumlah.

Ini adalah proposal tentang cara gofmt memformat if err != nil

(Ini bukan opini tentang proposal try().)

Saat pernyataan if mengembalikan nilai kesalahan satu baris bukan nol, seperti:

err := myFunc()
if err != nil {
    return err
}

gofmt dapat melonggarkan aturan pernyataan if-nya sendiri dan memformatnya pada satu baris seperti ini:

err := myFunc()
if err != nil { return err }

Tiga baris kode penanganan kesalahan menjadi hanya satu baris. Lebih sedikit kekacauan. Lebih mudah untuk mengikuti alur program.

Perlu ada penilaian tentang di mana harus menarik garis (permainan kata-kata) dengan ini
perubahan aturan gofmt. Ini mungkin termasuk beberapa dekorasi, seperti:

err := myFunc()
if err != nil { return fmt.Errorf("myFunc() blew up! %v", err }

Tetapi penanganan kesalahan multi-baris yang rumit harus tetap apa adanya: multi-baris dan jelas dan eksplisit.

Proposal _try_ telah ditarik: https://github.com/golang/go/issues/32437#issuecomment -512035919

Generik siapa?

Ini adalah proposal tentang cara gofmt memformat if err != nil

Saya telah mencobanya, karena kodenya bahkan lebih tidak dapat dibaca seperti itu daripada dengan pemformatan multi-baris. mencoba jauh lebih baik daripada solusi itu.

IMO masalahnya di sini bukan bagaimana penanganan kesalahan dilakukan, tetapi apakah itu diabaikan . Tidakkah mungkin membiarkan sintaks if err != nil apa adanya, tetapi membatasi ketidaktahuan tentang pengembalian Error ? Seperti menjadikannya peringatan/kesalahan kompiler dengan opsi deseverity untuk kode lawas.

IMO masalahnya di sini bukan bagaimana penanganan kesalahan dilakukan, tetapi apakah itu diabaikan . Tidakkah mungkin membiarkan sintaks if err != nil apa adanya, tetapi membatasi ketidaktahuan tentang pengembalian Error ? Seperti menjadikannya peringatan/kesalahan kompiler dengan opsi deseverity untuk kode lawas.

Banyak orang ingin linter menunjukkan kesalahan yang diabaikan.

Saya lebih suka membuat ini kesalahan yang sulit, tetapi melihat banyak warisan yang sudah ditulis, linter juga adil.

saya menemukan https://github.com/kisielk/errcheck berharga untuk memberi tahu saya tentang kesalahan yang tidak tertangani @plyhun @sorenvonsarvort

Seperti yang terlihat dalam diskusi di #32437, proposal ini berlaku untuk saat ini. Penutupan. Jika masalah muncul lagi, proposal baru dapat dibuka.

Saya mulai berpikir bahwa salah satu alasan mengapa banyak proposal merasa tidak sesuai adalah karena mereka sebenarnya mencoba untuk mengatasi dua masalah yang berbeda pada saat yang sama. Di satu sisi, memang benar bahwa memiliki blok err != nil setelah hampir setiap pemanggilan fungsi dapat memecah aliran kode dengan cara yang aneh, meskipun tentu ada kelebihannya, tapi saya pikir itu hanya setengah dari masalah. Masalah lainnya adalah menangani banyak pengembalian, terlepas dari apakah ada kesalahan yang terlibat atau tidak, bisa sangat kikuk.

Beberapa fungsi pengembalian terasa sangat, sangat berbeda dari fungsi pengembalian tunggal, meskipun ada perbedaan kecil di antara keduanya. Ini seperti jika ada batasan tambahan pada fungsi pemanggilan yang membutuhkan lebih dari satu argumen. Rasanya sangat aneh untuk dihadapi kadang-kadang. Saat Anda memanggil fungsi dengan beberapa nilai pengembalian, Anda hampir selalu perlu melakukannya pada barisnya sendiri, dan itu, dikombinasikan dengan := , sering menjadi sumber utama dari berbagai masalah bayangan variabel yang telah dibahas di tempat lain . Anda tidak dapat menghubungkan panggilan metode ke mereka, Anda tidak dapat menetapkan dari mereka secara langsung ke bidang struct dan variabel baru pada baris yang sama, dan seterusnya.

Saya tidak tahu. Mungkin hanya aku. Tapi saya telah menggunakan Go selama hampir 10 tahun sekarang dan memanggil fungsi dengan banyak pengembalian terkadang masih terasa canggung bagi saya.

Terima kasih!

Sebenarnya ada satu masalah dengan if err != nil , ruang lingkup err dapat hidup lebih lama dari yang seharusnya. Saat Anda menyejajarkan if itu menyelesaikan masalah, tetapi tidak semua kasing dapat disejajarkan.

if err := foo(); err != nil {
if _, err := bar(); err != nil {



md5-6a135eb952fe7b24b3389cb16d3244a1



a, err := bar()
if err != nil {



md5-d52f811d3e31bb368bd8045cfb2e93b4



var err error
baz.A, err = bar()
if err != nil {

Variabel err seharusnya tidak ada dalam lingkup fungsi setelah blok if err != nil {} selesai. Inilah proposal saya yang dibuat dari proposal try() untuk memperbaiki masalah https://github.com/golang/go/issues/33161. Saya akan menyukai beberapa umpan balik yang membangun.

Variabel err tidak boleh ada dalam cakupan fungsi setelah blok if err != nil {} selesai.

mengapa "harus" tidak ada setelah blok if selesai? Kompiler dapat mengoptimalkannya (jika dianggap perlu), dan tidak ada beban mental saat blok err := stmt()\nif err != nil {} selesai karena blok ini hampir selalu berjalan bersamaan.

Saya belum melihat proposal Anda secara mendalam (meskipun pujian untuk upaya menulisnya!). Namun, seperti yang juga saya uraikan dalam komentar saya di atas, saya pikir penelitian lebih lanjut diperlukan untuk mengatasi masalah yang dirasakan, sebelum kita menggali proposal untuk menyelesaikannya.

Kesalahan @Freeaqingme seharusnya tidak ada setelah blok if err != nil selesai, sebagian besar karena kami sudah bertindak seolah-olah tidak.

Dalam contoh CopyFile, ada r, err := os.Open(src) diikuti oleh w, err := os.Create(dst) . err membayangi yang pertama. Variabel bayangan biasanya tidak disukai.

Ada juga keanehan lainnya. Jika saya memiliki err := foo() dan kemudian sesuatu seperti bar.V, err = baz() , jika kode di-refactored dan saya tidak lagi membutuhkan foo() saya perlu menambahkan var err error sebelum baz baris. . Saya tidak berpikir bahwa refactoring lokasi yang berbeda dalam suatu fungsi harus mempengaruhi tempat lain seperti itu.

Secara teknis dalam

    r, err := os.Open(src)
    if err != nil {
        return ...
    }
    w, err := os.Create(dst)

contoh kedua dari err tidak membayangi contoh pertama. Mereka sebenarnya adalah variabel yang sama. Lihat pembahasan tentang mendeklarasikan ulang variabel di https://golang.org/ref/spec#Short_variable_declarations.

func melakukanSesuatu() {
r, err := os.Buka(nama file)
panic(fmt.Errorf(err, "gagal membuka file: %s", nama file)) //
Di sini panik.

}

Pada Kamis, 10 Oktober 2019 pukul 11:24 clearcode [email protected] menulis:

Saya pikir kita dapat menambahkan fungsi buildin:

menegaskan()

contoh:

func doSomeThing() kesalahan {

r, err := os.Open(filename)
assert(err, "failed to open file: %s", filename) // in this step, just return the error

resp,err := http.Get(someURL)
menegaskan(err, "permintaan gagal")

}

dan fungsi lain yang tidak mengembalikan kesalahan:

func melakukanSesuatu() {
r, err := os.Buka(nama file)
assert(err, "gagal membuka file: %s", nama file) // Di sini panik.

}

jadi assert(error, args ...interface{}) lebih baik dari: if err != nil ; {
kembalikan kesalahan }


Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/golang/go/issues/32825?email_source=notifications&email_token=AGUV7XQ5HO7GL3YP72R7BV3QN2N55A5CNFSM4H4DL33KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTLEK5WWUZGODN5WXHJKT41
atau berhenti berlangganan
https://github.com/notifications/unsubscribe-auth/AGUV7XS4JMK44QHIIR3RSGTQN2N55ANCNFSM4H4DL33A
.

Kesimpulannya adalah saya ingin melihat kesalahan aktual yang dikembalikan saat ini
fungsi pada baris saat ini.

Pada Jum, 11 Okt 2019 jam 09:55 Aaaa Einai [email protected] menulis:

func melakukanSesuatu() {
r, err := os.Buka(nama file)
panic(fmt.Errorf(err, "gagal membuka file: %s", namafile)) // Disini panik.

}

Pada Kam, 10 Okt 2019 jam 11:24 clearcode [email protected]
menulis:

Saya pikir kita dapat menambahkan fungsi buildin:

menegaskan()

contoh:

func doSomeThing() kesalahan {

r, err := os.Open(filename)
assert(err, "failed to open file: %s", filename) // in this step, just return the error

resp,err := http.Get(someURL)
menegaskan(err, "permintaan gagal")

}

dan fungsi lain yang tidak mengembalikan kesalahan:

func melakukanSesuatu() {
r, err := os.Buka(nama file)
assert(err, "gagal membuka file: %s", nama file) // Di sini panik.

}

jadi assert(error, args ...interface{}) lebih baik dari: if err != nil ; {
kembalikan kesalahan }


Anda menerima ini karena Anda berkomentar.
Balas email ini secara langsung, lihat di GitHub
https://github.com/golang/go/issues/32825?email_source=notifications&email_token=AGUV7XQ5HO7GL3YP72R7BV3QN2N55A5CNFSM4H4DL33KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTLEK5WWUZGODN5WXHJKT41
atau berhenti berlangganan
https://github.com/notifications/unsubscribe-auth/AGUV7XS4JMK44QHIIR3RSGTQN2N55ANCNFSM4H4DL33A
.

Terus terang, saya tidak ingin pengembalian implisit yang diberikan try . Jika kami memiliki obat generik, saya lebih suka solusi yang menggunakan perilaku monad-ish sebagai gantinya.

type Result<T> interface {
  Expect(err error) T
  OrElse(defaultValue T) T
}

func From<T>(value T, err error) Result<T> { ... }

Bagi saya, ini jauh lebih bersih daripada builtin yang saat ini diusulkan, meskipun perubahan lebih lanjut akan diperlukan di atas karena Anda akan memiliki proliferasi metode yang mengembalikan (nilai, kesalahan) dan Hasil

Ini sangat mirip dengan Rust's Ok and Err.
Saya pikir if err != nil {} mungkin lebih baik sedikit.

@Yanwenjiepy itu disengaja, saya penggemar berat tipe Result Rust.

Saya kurang dari 10 menit untuk belajar Go. Hal pertama yang saya perhatikan dalam kode yang saya lihat adalah salinan ini ditempelkan berulang kali:

someValue, err := someFunction();
if err != nil {
  panic(err)
}

Saya jelas bukan ahli, tetapi mungkin berharga bahwa saya hanya perlu melihat sekilas untuk berakhir di utas ini.

Itu karena Anda melihat cuplikan kode untuk dipelajari. Kode nyata harus menangani kesalahan, bukan hanya panik dan crash.

Benar, tetapi kesalahan dapat (dan sering kali harus) dikelompokkan. Itu sebabnya blok coba/tangkap ada dalam bahasa lain. Misalnya, berikut ini baunya kurang seperti dinosaurus bagi saya:

try {
  foo, throw err := someFunction();
  bar, throw err := foo.get();
  baz, throw err := bar.make();
  qux, throw err := baz.transform();
} catch(err) {
  // "Unable to foo bar baz qux."
  tryHarder();
}

Sekali lagi, awam total. Tetapi kode hanyalah simbol, dan jika cukup berulang, Anda juga dapat membuat simbol untuk itu. Ini tampaknya menjadi simbol yang sangat sering berulang.

Anda mungkin ingin melihat posting Rob Pike Errors Are Values untuk melihat bagaimana Anda dapat menggunakan helper untuk menggabungkan kesalahan dan menangani semuanya sekaligus. Dalam praktiknya, menangkap semua pengecualian dengan satu klausa dianggap sebagai gaya yang buruk di sebagian besar bahasa yang memilikinya, karena Anda akhirnya menyembunyikan informasi tentang apa yang sebenarnya terjadi. (Dan jika Anda memperluas contoh untuk memecahkan pengecualian yang ditangkap individu dan tidak membuang informasi itu, kode akan berakhir selama Go yang setara.)

Terima kasih untuk tautannya. errWriter adalah solusi yang benar-benar lumayan.

Benar, tetapi kesalahan dapat (dan sering kali harus) dikelompokkan. Itu sebabnya blok coba/tangkap ada dalam bahasa lain. Misalnya, berikut ini baunya kurang seperti dinosaurus bagi saya:

try {
  foo, throw err := someFunction();
  bar, throw err := foo.get();
  baz, throw err := bar.make();
  qux, throw err := baz.transform();
} catch(err) {
  // "Unable to foo bar baz qux."
  tryHarder();
}

Sekali lagi, awam total. Tetapi kode hanyalah simbol, dan jika cukup berulang, Anda juga dapat membuat simbol untuk itu. Ini tampaknya menjadi simbol yang sangat sering berulang.

Katakanlah setiap fungsi mengembalikan jenis kesalahan yang tumpang tindih dan Anda harus menangani semua hasil fungsi dengan anggun, bagaimana Anda menulis tryHarder()?

try {
  foo, throw err := someFunction();  // err could be TypeA and TypeB
  bar, throw err := foo.get();       // err could be TypeB and TypeC
  baz, throw err := bar.make();      // err could be TypeA and TypeC
  qux, throw err := baz.transform(); // err could be TypeB and TypeD
} catch(err) {
  tryHarder(); // tell me how to handle each error?
}

Hanya perlu 1 menit bagi orang lain untuk memahami kode di bawah ini:

foo, err := someFunction();  // err could be TypeA and TypeB
if err != nil {
 // handle err
}

bar, err := foo.get();       // err could be TypeB and TypeC
if err != nil {
  // handle err
}

baz, err := bar.make();      // err could be TypeA and TypeC
if err != nil {
  // handle err
}

qux, err := baz.transform(); // err could be TypeB and TypeD
if err != nil {
  // handle err
}

Katakanlah setiap fungsi mengembalikan jenis kesalahan yang tumpang tindih dan Anda harus menangani semua hasil fungsi dengan anggun

Dalam contoh itu, Anda benar sekali.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat