- Go'daki
if err!= nil tekrarları yıllardır kullanıcı anketlerinde büyük bir şikayet olarak kalmış olsa da, Go ekibi hata işleme sözdizimini değiştirmeyi şimdilik ilerletmeme kararı aldı
- 2018'deki
check/handle, 2019'daki try, 2024'teki ? önerileri yeterli uzlaşı sağlayamadı; özellikle try, gizli kontrol akışı nedeniyle güçlü tepki çekti
- Go öneri sürecinde genel uzlaşı yoksa öneriler genelde reddedilir ve Google'ın kıdemli Go ekibi üyeleri arasında bile şu anda en iyi yönün ne olduğu konusunda oybirliği yok
- Mevcut durumu savunanlar, Go'nun zaten çalışan bir hata işleme yöntemine sahip olduğunu ve yeni sözdiziminin kod stili, hata ayıklama, dokümantasyon, araçlar ve mevcut kod üzerinde büyük maliyet yaratacağını düşünüyor
- Go ekibi, hata işleme sözdizimini ana hedef yapan açık önerileri ve yeni önerileri ek inceleme yapmadan kapatacak ve daha net bir problem tanımı oluşana kadar diğer iyileştirme fırsatlarına odaklanacak
if err != nil'in yarattığı eski şikayet
- Go'da en uzun süredir devam eden şikayetlerden biri, hata işleme kodunun aşırı ayrıntılı olması
- Temsili kalıp şu şekilde
x, err := call()
if err != nil {
// handle err
}
- API çağrılarının çok olduğu ve hataların basitçe geri döndürüldüğü programlarda
if err != nil, kodun geri kalanına baskın gelebilir
- Örnek
printSum fonksiyonunda, gövdenin 10 satırından gerçekten iş yapan satırlar çağrı, çıktı ve dönüş dahil 4 satır; kalan 6 satır ise gürültü gibi görünüyor
- Go'nun yıllık kullanıcı anketlerinde hata işleme yıllarca en üst düzey şikayetlerden biri oldu; bir dönem generics eksikliği bunun önüne geçmişti ama Go generics desteği kazandıktan sonra hata işleme yeniden en üst sıradaki şikayet haline geldi
Üç büyük sözdizimi önerisi
- Go ekibinin ilk açık girişimi, 2018'de Go 2 çalışmasının parçası olarak Russ Cox'un sorunu resmi olarak özetlemesiyle başladı
- Marcel van Lohuizen'in taslak tasarımı,
check ve handle mekanizmalarına dayanıyordu ve diğer dillerdeki yaklaşımlarla alternatiflerin analizini de içeriyordu
func printSum(a, b string) error {
handle err { return err }
x := check strconv.Atoi(a)
y := check strconv.Atoi(b)
fmt.Println("result:", x + y)
return nil
}
check/handle yaklaşımının fazla karmaşık olduğuna karar verildi ve 2019'da daha basit bir try önerisi ortaya çıktı
check benzeri anahtar sözcük, yerleşik try fonksiyonuna dönüştü
handle kısmı çıkarıldı
- Mevcut hata işleme kodunu
try biçimine dönüştüren tryhard aracı geliştirildi
- İlgili GitHub sorunu yaklaşık 900 yorumla hararetli şekilde tartışıldı
func printSum(a, b string) error {
// use a defer statement to augment errors before returning
x := try(strconv.Atoi(a))
y := try(strconv.Atoi(b))
fmt.Println("result:", x + y)
return nil
}
try, hata olduğunda çevreleyen fonksiyondan dönüş yaparak kontrol akışını etkiliyordu ve derin iç içe geçmiş ifadelerin içinde bile dönüş gerçekleşebildiği için birçok kullanıcı bunu kabul etmekte zorlandı
- O dönemde yeni bir anahtar sözcük eklemek daha iyi olabilirdi; bugün ise
go.mod dosyası ve dosya başına yönergelerle dil sürümü daha ayrıntılı kontrol edilebiliyor
- Jimmy Frasche'nin yakın tarihli önerisi, özgün
check/handle tasarımına geri dönüp bazı eksileri gidermeye çalışıyor
try sonrasında süreç muhasebesi ve ? önerisi
try önerisinden sonra Russ Cox, “Thinking about the Go Proposal Process” yazı dizisiyle öneri sürecini yeniden değerlendirdi
- “Go Proposal Process: Large Changes”,
tryın uygulama takvimine bağlanmış bir öneri değil, ikinci bir taslak tasarım olması gerektiğini savunuyor
- Sonraki yıllarda Go ekibi hata işleme sözdizimini değiştirmeyi ilerletmedi; topluluktan ise benzer, ilginç, anlaşılması zor ya da uygulanamaz öneriler gelmeye devam etti
- Ian Lance Taylor, hata işleme iyileştirme önerilerinin durumunu toplamak için bir umbrella issue oluşturdu; ilgili geri bildirim ve tartışmaları derleyen bir Go Wiki de ortaya çıktı
- Sean K. H. Liao'nun “go error handling proposals” yazısı, yıllar boyunca çok sayıdaki hata işleme önerisini izliyor
- Şikayetler sürünce Ian Lance Taylor, 2024'te
? kullanarak hata işleme boilerplate'ini azaltma önerisini sundu
- Gösterim, Rust'ın
? operatöründen ödünç alınmıştı
- Küçük ölçekli gayriresmi kullanıcı araştırmasında katılımcıların çoğu,
? kullanılan Go kodunun anlamını doğru tahmin etti
- Genel Go kodunu yeni sözdizimine dönüştüren bir araç ve bir derleyici prototipi de geliştirildi
func printSum(a, b string) error {
x := strconv.Atoi(a) ?
y := strconv.Atoi(b) ?
fmt.Println("result:", x + y)
return nil
}
- Bu öneri de hızla çok sayıda yorum ve tercihe dayalı ayrıntı değişikliği önerisiyle doldu; Ian öneriyi kapattıktan sonra içeriği discussion başlığına taşıdı
- Biraz revize edilen sürüm biraz daha olumlu tepki aldı ama geniş destek sağlayamadı
Neden şimdi durmak istiyorlar
- Go ekibi, öngörülebilir gelecekte hata işlemenin sözdizimsel sorununu çözme girişimlerini durdurmaları gerektiği sonucuna vardı
- Öneri süreci bu kararı destekliyor
- Öneri sürecinin amacı, zamanında sonuç üzerinde genel uzlaşıya ulaşmak
- Sorun takip sistemi tartışmalarında genel uzlaşı bulunamazsa öneri genelde reddediliyor
- Ne uzlaşı ne de sonraki adım bulunursa, Go mimarları tartışmayı inceleyip kurum içi uzlaşı arıyor
- Hata işleme önerilerinin hiçbiri uzlaşıya yakın destek alamadı ve hepsi reddedildi
- Google'ın kıdemli Go ekibi üyeleri arasında bile şu anda en iyi ilerleme yönü konusunda oybirliği yok; güçlü bir uzlaşı olmadan makul şekilde ilerlemek mümkün görülmüyor
Mevcut durum ve değişim için argümanlar
- Mevcut durumu savunan tarafta, Go'nun olgunluğu ve ekosistem maliyeti gibi pratik gerekçeler var
- Go, ilk döneminde hataya özel sözdizimsel şeker ekleseydi bugün tartışma daha az olabilirdi; ancak Go artık 15 yaşında ve hâlihazırda çalışan bir hata işleme yöntemine sahip
- Bugün kusursuz bir çözüm bulunsa bile, memnuniyetsizlik bu kez değişimi isteyenlerden değil mevcut durumu tercih edenlerden gelebilir
- Generics, kullanıcıların doğrudan yazmasını zorunlu kılmaz; ama yeni hata işleme sözdizimi kullanılmazsa kod alışılmadık görünebilir, bu yüzden fiilen çoğunluğun kullanması gerekebilir
- Bu da Go'nun aynı işi yapmanın birden çok yolunu sunmamaya çalışan tasarım ilkesiyle çatışabilir
:= kısa değişken tanımındaki yeniden bildirim özelliği, hata işlemeyle doğan bir sorunu çözmek için eklenmişti
- Yeniden bildirim olmasaydı, art arda hata denetimlerinde farklı
err adları ya da ayrı değişken tanımları gerekirdi
- O dönemde hata işleme için daha iyi sözdizim desteği olsaydı yeniden bildirim kuralı ve buna bağlı karmaşıklık da gerekmeyebilirdi
- Hatalar uygun şekilde zenginleştirilip işlenirse salt tekrarın payı azalıyor
- Kullanıcı anketlerinde hatalarda stack trace bulunmamasına dair tekrarlanan geri bildirimler var
- Yardımcı fonksiyonlarla zenginleştirilmiş hatalar üretip döndürmek mümkün
fmt.Errorf("invalid integer: %q", a) gibi giriş değeri bilgisini eklemek, boilerplate'in göreli ağırlığını küçültüyor
- Standart kütüphane özellikleri de hata işleme boilerplate'ini azaltabiliyor
- Bu, Rob Pike'ın “Errors are values” yaklaşımıyla aynı yönde
- Bazı durumlarda birden çok hatayı tek seferde ele almak için
cmp.Or kullanılabiliyor
- Yazmak, okumak ve hata ayıklamak farklı etkinlikler
- Tekrarlayan hata denetimlerini yazmak sıkıcı olsa da, IDE'ler ve LLM destekli kod tamamlama temel hata denetimlerini kolayca üretebiliyor
- Okurken ayrıntı fazlalığı daha belirgin oluyor; IDE'ler hata işleme kodunu gizlemek için aç/kapat seçeneği sunabilir
- Hata ayıklarken ayrı bir
if deyimi zaten varsa println eklemek ya da breakpoint koymak kolay
- Hata işleme
check, try ya da ? arkasına gizlenirse, çoğu zaman tekrar if deyimine çevirmek gerekebilir; bu da hata ayıklamayı zorlaştırabilir veya ince hatalara yol açabilir
- Dil değişiklikleri yalnızca tasarım ve uygulama maliyeti getirmiyor; mevcut kodun değiştirilmesi, dokümantasyonun güncellenmesi ve araçların uyarlanması da gerekiyor
- Go ekibi görece küçük ve önlerinde başka öncelikler de var
- Öncelikler ve ekip büyüklüğü zamanla değişebilir
- Google Cloud Next 2025'te Go ekibinin görüştüğü bazı Go kullanıcıları, daha iyi hata işleme uğruna dilin değiştirilmemesi gerektiğini güçlü biçimde söyledi
- Bu kişiler, başka dillerden yeni geldiklerinde Go'da özel hata işleme sözdizimi olmamasının en çok göze çarpan şey olduğunu, ancak daha idiomatic Go kodu yazdıkça bunun öneminin azaldığını belirtti
- Bu örneklem temsili olacak kadar büyük değil ama GitHub'da görülen kişilerden farklı bir grup olabilir
- Değişimi savunan argümanlar da hâlâ geçerli
- Daha iyi hata işleme desteğinin yokluğu, kullanıcı anketlerinde en üst sıradaki şikayetlerden biri olmaya devam ediyor
- Yalnızca karakter sayısını azaltmaya odaklanan yaklaşımlar yanlış yön olabilir
- Temel hata işlemenin anahtar sözcükle daha görünür hale gelmesi ve
err != nil boilerplate'inin kalkması, kod incelemelerinde hata işlemenin yapılıp yapılmadığını görmeyi kolaylaştırabilir
- Sorunun özünün yalnızca sözdizimsel ayrıntı fazlalığı mı olduğu, yoksa API'ler ile geliştirici ve son kullanıcı için anlamlı hatalar oluşturan iyi hata işlemenin doğası gereği ayrıntılı olması mı olduğu henüz yeterince anlaşılmış değil
Go ekibinin kararı
- Şimdiye kadar hata işlemeyi ele alan hiçbir girişim yeterli ivme kazanamadı
- Go ekibi, ortak bir problem anlayışının eksik olduğunu ve hatta ortada gerçekten bir problem olup olmadığı konusunda bile herkesin hemfikir olmadığını düşünüyor
- Öngörülebilir gelecekte hata işleme için sözdizimsel dil değişiklikleri ilerletilmeyecek
- Hata işleme sözdizimini ana hedef yapan açık öneriler ve bundan sonra gelecek öneriler ek inceleme olmadan kapatılacak
- Topluluğun keşif ve tartışmaları hata işleme sözdizimi değişikliğine dönüşmemiş olsa da, Go dili ve süreçlerinde çeşitli iyileştirmelere yol açtı
1 yorum
Hacker News görüşleri
Go ekibine “şöyle yapsalardı olurdu” tarzı önerileri hafifçe ortaya atmak istiyorsanız, önce yazıda bağlantısı verilen wiki sayfasına https://go.dev/wiki/Go2ErrorHandlingFeedback ve GitHub issue aramasına https://github.com/golang/go/issues?q=+is%3Aissue+label%3Aerror-handling bakmanızı isterim.
Şu anda önermeyi düşündüğünüz şey neredeyse kesinlikle ilk kez ortaya çıkmıyor; önemli bir kısmının zaten derinlemesine incelenmiş olma ihtimali yüksek.
Go ekibinin bu dürüst yaklaşımını olumlu buluyorum ve işte hâlâ her gün Go’yu keyifle kullanıyorum.
En çok yorum alan birkaç GitHub issue sayfasında da benzer bir şey görünmüyordu; Go ekibi dil tasarımının sihirbazı olduğu için buradaki insanların gelişigüzel ortaya attığı çözümleri elbette incelemiştir demek fazla iddialı olur.
Go ekibi Java’nın yaptığına benzer bir hata yaptı: statik tipli olup parametrik polimorfizme sahip olmama sorunu. Bu hata işleme probleminin kökü de orada; ama ellerini kaldırıp bunu düzeltmiyorlar gibi görünüyor.
Kulağa gösterişli ve ürkütücü gelebilir ama hataları işlenebilecekleri yere kadar iletirken unutulmamalarını da sağlayan zarif ve fonksiyonel olarak saf bir yöntem.
Haskell kodu yazanlar için bu o kadar yerleşik bir yöntem ki, Go topluluğunda bunu bilip seven kimsenin olmamasını anlamıyorum.
Sayfanın kendisi ve bağlantılar için teşekkürler; ama kendi dillerine bu kadar önem veren insanların böylesine iyi yerleşmiş bir çözümü atlaması kafa karıştırıcı geliyor.
Neredeyse her dilin kendine göre daha iyi bir yöntemi var; mesele sadece karar verememek ya da herkesi memnun edememek mi, yoksa Go dilinin kendisinde diğer dillerin çözümlerinin uymamasına yol açan somut bir neden mi var, bilmek isterim.
Gerçekte ise neredeyse her durumda onlar çok daha fazlasını biliyor.
Amatörler, en çok özelliğin tıkıştırıldığı dilin en iyi dil olduğunu safça düşünür; özellikle de kendi zevklerine uygun özellikler eklenmişse bunu daha da böyle görürler.
Bu, bıçak yapımına yeni başlamış birinin Japon şef bıçağına bakıp onu yetersiz bulduktan sonra, parmak oyukları, gizli bölme, çakmak ve Bluetooth hoparlörlü 3D baskı bir sap eklerse daha iyi olacağını düşünmesine benziyor.
Bir onay kutusu listesi oluşturup her maddeyi tartışarak doldurursunuz; ölümcül bir semantik hata ya da soundness açığı bulunmadığı sürece de geri çıkarmazsınız.
Hepsi dolduğunda uygularsınız;
.awaitmi olsun,/awaitmi olsun,.await!()mı olsun diye konuşan insanlar da tekrar ortadan kaybolur.Rust böyle işler; bazı issue’lar 10 yıldan fazla gecikse de sonunda maddeler doldurulur ve en güncel nightly’de kararlı hâle gelir.
Go, herkesin hemen çarptığı tek bir problemi, birkaç tane yüksek kaliteli öneri varken içlerinden birini seçemeyip bikeshedding’in bitmesini beklediği için çözemiyorsa, o süreç komedidir.
Onay kutusu gereksinimlerini karşıladı diye öylece eklenen bir özellikler koleksiyonu değildir.
Rust, C++ gibi karmakarışık hâle gelmiş olacak mı? Go, çıktığı zamanki gibi zamana direnen bir dil olarak kalacak mı?
Ankette hata işlemeden bahsedenlerin oranı %13’tü; ayrıca mevcut yöntemi olduğu gibi tercih edenler de var.
https://go.dev/blog/survey2024-h1-results
Daha önce, içteki fonksiyonun hata döndürmesini bekleyen tuhaf bir Go fonksiyonu yazmıştım
Bu yüzden içteki fonksiyon hata döndürmezse dıştaki fonksiyonun hata döndürmesi ve başka işlemler yapması gerekiyordu; içteki fonksiyon hata döndürürse de nil döndürmeliydi
Özetle
if err != nil { ... }değil,if err == nil { // return an error }yazmam gerekiyordu; ama alışkanlıkla ilkini yazdım ve hata ayıklamak epey uzun sürdüÇünkü
if err != nilifadesine o kadar duyarsızlaşmıştım ki beynim, o kalıbın orada olmaması gerektiği ihtimalini hiç değerlendirmediBu yüzden yaygın ifadeler için sözdizimsel şeker gerektiğini düşünüyorum. Çok yaygın
if err != nilile nadirif err == nilarasındaki fark daha belirgin olsaydı gerçekten yardımcı olurduif err == nilher yazdığımda göze çarpsın diye// invertedyorumunu ekliyorumBunun dil düzeyinde ele alınması güzel olurdu, ama en azından daha görünür kılmanın bir yolu olarak paylaşıyorum
if fruit != "Apple" { ... }de aynı durumu yaratabilirBunu iyileştirecek genel bir çözüm olup olmadığını merak ediyorum; bunu yalnızca hata işlemeye özgü bir sorun olarak görmek biraz hedefi ıskalamak gibi
Hatalarda özel ya da benzersiz bir şey yok; diğerleri gibi yalnızca bir durum
Yaygın bir
if err == nil { return ... }kalıbı oluşursa bu kez o kodun her yerine yayılmış olacakMevcut çözüm gayet iyi; sanırım bundan hoşlanmayanlar çoğunlukla Go'ya yeni başlayanlar ya da başlangıç seviyesindekiler
Çevremdekiler açık, net ve okunması kolay “uzun” hata işlemeyi seviyor
if err != nilifadesini tek, küçük bir ligatür simgesi gibi vurgulayabilir ya da arka planda soluk gösterebilirBöylece
if err == nilgibi tam olarak o dizgeden farklı biçimler tam tersine göze çarparif err … {gibi katlanmış bir gösterimle de çözülebilir gibi görünüyorGo'nun açık hata işleme biçimini seviyorum
Bir fonksiyon ya her zaman başarılıdır ya da başarılı veya başarısız olabilir. Her zaman başarılı olan fonksiyon basittir; başarısız olabilen bir fonksiyon başarısız olursa dıştaki kod başarısız durumla devam edemez, dolayısıyla bunu işlemelidir
Diller burada ayrışıyor. Birçok dil istisna fırlatıp biri açıkça yakalayana kadar yukarı taşır ve bir tür stack trace sağlar
Go'da kod yazarken her zaman seçmek zorunda olduğunuz seçenekler olmasını seviyorum: hatayı yok sayıp devam etmek (
foo, _ := doSomething()), anlamlı bilgi olmadan erken dönmek (return nil, err), faydalı bağlam ekleyerek erken dönmek, gelen hatayı yorumlayıp dallanmakÖrneğin veritabanında güncellenecek satır bulunamazsa servis katmanı not found hatası döndürebilir ve API'de bu 404 olur; ya da idempotent bir silme fonksiyonu not found durumunu başarı olarak yorumlayabilir
Go 2 ya da başka bir dil olsaydı, nil olabilen tuple yerine Rust/Swift tarzı bir Result tipi ve her zaman doğrudan
errorkullanmak yerine daha iyi tiplendirilmiş ve numaralandırılabilir hata tipleri olmasını isterdimAncak Go 1'in idiomatik tuple dönüşlerinin üstüne Result eklenirse aynı işi yapmanın birden fazla yolu ortaya çıkar, bu da kafa karışıklığı ve bölünme yaratır; bu yüzden Go 2'ye ya da yeni bir dile daha uygun
Stack'in alt katmanları genellikle ne yapacağını bilmez, bu yüzden hatayı işlememelidir
Hatayı işleme politikası sonunda hatayı sarmalayıp stack'te yukarıya yeniden döndürme politikasına dönüşmeye meyillidir ve ciddi bir angaryaya dönüşür
Go hataları tamamen yok saymaya izin verir ve bunun sonucu çökme olabilir
Sağlam yazılım yapmak için gereksinimi tam olarak işaret edip yine de Go'nun hata işleme biçimini sevdiğini söylemek biraz anlaşılır gelmiyor
[1]: https://borgo-lang.github.io/ | https://github.com/borgo-lang/borgo
Tüm fonksiyonel diller, Rust gibi birçok modern dil, hatta checked exception'a sahip Java bile bunu sunuyor
Generics olan bir dilde Go tarzı “hata işleme” büyük ölçüde kopyalanabilir ve muhtemelen daha iyi kod çıkar
Cevap JavaScript ya da Python ise, bu yaygın bir karşılaştırma kalıbı tabii
Go için doğru karar bu. Go ile ilk tanıştığımda hata işlemeyi sevmemiştim, ama şimdi gerçekten sever oldum
Fikrimi değiştiren iki şey oldu. https://go.dev/blog/errors-are-values yazısını okuyup “hatalar değerdir” bakış açısını gerçekten benimsedim ve bunun üzerine bir ölçüde popüler olan https://github.com/stytchauth/sqx paketini de yaptım
Ayrıca gerçekten mantıksız, geçersiz durumlar için
panic(err)kullanmaya yavaş yavaş alıştımÜst kodun nasıl işleyeceğine dair hiçbir sezgisi olmadığı saçma durumların hepsini zorla ele aldırmanın gereği yok; iyi yerleştirilmiş bir iki panic ile kod tabanındaki yüzlerce hata kontrolü kaldırılabilir
Örneğin ctx içinde varsayılan logger olup olmadığı gibi bir konuyu düşünebiliriz
Aksine iyileştirme ihtimali yüksek
bash'te de
-evarEskiden C#'ı ilk kullanırken try/catch/finally akışını, using'i, iç içe kullanımı, catch içinde hata olursa ne olacağını, finally içinde olursa ne olacağını anlamanın akıllıca olduğunu düşünürdüm
Artık bunları düşünmemek daha iyi geliyor
Bu yazının Go’da hata işlemenin ana sorununun sözdiziminin fazla laf kalabalığı olmasıymış gibi konuşmasını sevmiyorum. O kısmı pek umursamıyorum
Daha önemli olan, hataların sessizce çöpe atılabilmesi ya da yanlışlıkla yok sayılabilmesi; fonksiyon çağrısı sonucunun bir değer olmaması nedeniyle kolayca saklanıp aktarılamaması;
errors.Is’e ihtiyaç duyulması ve “iç içe geçmiş” hataların tamamının tip sistemiyle pek uyuşmayan tuhaf bir çalışma zamanı düzeneği olmasıHatalar üzerinde switch yapmak da zor; standart kütüphane sentinel değerler kullanıyor ve generics ile etkileşimi iyi olmadığı için errgroup gibi paketlere ihtiyaç doğuyor
Atladığım başka bir şey var mı?
İstisnaları olan bir dilde olsaydı kimse bunu yapmazdı
Öngörülebilir gelecekte hata işleme sözdizimini değiştirmeye yönelik daha fazla girişimde bulunmamaya karar verdiler; bu da hata olsun başka konular olsun, diğer sorunlara bakacak dikkat alanı açıyor
Go’nun evrimi buzul kadar yavaş ve birçok kişi için bu bir hata değil, özellik
“Hatalarda stack trace olmamasına dair anket görüşleri, yardımcı fonksiyonun zenginleştirilmiş hatalar oluşturup döndürmesini sağlayarak çözülebilir” türü açıklama komik
if err != nil { return fmt.Errorf("invalid integer: %q", a) }gibi stack trace’i elle sağlama işine “hata işleme” demeleri eğlenceliGo ekibinin tanımına göre istisnalar hataları otomatik işliyor sayılır. Elbette C++ dışındaki dillerde
Öyle olabilir ama gerçekten hepsine ihtiyaç var mı? Log maliyeti ne olacak?
Framework ve runtime gürültüsünü kesip atan tek satırlık sarmalanmış bir hatanın çok daha iyi olduğunu düşünüyorum
İyi sarmalanırsa araması da çok kolay olur ve genellikle stack trace’ten daha etkili biçimde iz sürdürür
Go’yu 10 yıldan fazla tam zamanlı kullanırken runtime fonksiyonlarına ya da çağrı stack’inin geveze gürültüsüne bir kez bile ihtiyaç duymadım
Bir Elixir geliştiricisinin bakış açısından bu delilik gibi görünüyor
Erlang/Elixir’de bu genellikle fonksiyonun
{:ok, result}veya{:error, description_or_struct}tuple’ı döndürmesiyle çözülürBuna Elixir’in
withifadesini ekleyince hata işlemeyi aşağıda toplayabilirsiniz; bu da okumayı çok daha iyi hale getirirGo da
withclause’una karşılık gelen bir şey ekleyip hata nil olduğu sürece fonksiyonları ilerletebilir, aşağıya da hata işleme clause’u koyabilirwithifadesini benimseme ihtimali hiç yok gibi görünüyorGo’nun generics, hata işleme, paket yönetimi gibi temel ve açıkça değerli yapıları topluluk mutabakatı eksikliği nedeniyle çok uzun süre ertelemesi ilginç
Generics, açık kaynak olarak yayımlanmasından sonra 13 yıl sürdü; 16 yıl geçmişken hâlâ hata işleme yok; paket yönetimi ise yaklaşık 9 yıl sürdü
Düşünüp taşınmanın da değeri var ama yayınlamanın da değeri var. GitHub’da 900 yorum yazan insanlar nihayetinde Go kullanmaya devam edecek ve dile bir şeylerin girmesi, sürekli ertelemekten muhtemelen daha iyi olurdu
Birden fazla dönüş tipine sahip bir fonksiyonla, sonucu değişkenlere atamak dışında yapabileceğiniz bir şey yok
Ama Erlang ve Elixir’de bunlar hiçbir yük getirmeden tamamen idiomatik bir yöntem
Hatta aslında ML ailesindekilerden çok daha güçlüler, çünkü oradaki sum type’lar açık
Bu tartışmayı ayrıntılı takip etmedim ama neden Rust tarzı yaklaşımı doğrudan benimsemediklerini anlamıyorum
Go'ya generics geldikten sonra benim hemen eklediğim yöntem de bu
Bağlantı verilen yazıda yalnızca “Rust'ta handle'a karşılık gelen bir şey yok ve
?operatörünün rahatlığı uygun işlemeyi atlama ihtimali doğurabilir” açıklamasını görüyorumAma kullanışlı olmasının hataları yok saymak anlamına gelip gelmediğini anlamıyorum
Go tarzı yaklaşımın sorununun yarısı, sonuçla ilgili hiçbir şeyi zorunlu kılmaması ve hata kontrolünü de yalnızca asgari düzeyde zorunlu kılması
x, err := strconv.Atoi("123"); fmt.Println("result:", x)declared and not used: errverir, ama ikinci dönüşümden sonraerrkontrol edilmese biley'nin varsayılan değeri 0 olduğu için sorun fark edilmeden gayet çalışabilirif err != nil { }gibi boş bırakılsa da derlenir ve çalışır; bir şeylerin yanlış olduğunu anlayamazsınızDönüş değerini Result yapmak, bir karar verilmesini zorunlu kılar. Birileri
!i hoyratça kullanıyor ya da?ile kolayca yukarı taşıyıp hata durumunu işlemiyor diye, o zamanpanici de mi yasaklayacağız?Ayrıca her tipin belirlenmiş bir sıfır değeri olması gerektiğine dair tuhaf takıntı yüzünden sum type da ekleyemiyorlar
?kullanımı kolay olursa artık kimsenin hataları sarmalamayacağı anlamına geldiğini anlıyorumÇok şüpheli bir mantık
En başta
?hata sarmalamayı teşvik edecek şekilde tasarlanabilirÖrneğin Rust'taki
Fromun Go'daki karşılığı nasıl görünmeli??görünürlüğü düşük ve kontrol akışı dallanmasını tek bir ifade ya da expression içinde gizliyorGo'nun ternary operatörü kaldırıp her dalın ayrı satırda olduğu
ifdeyimini seçmesinin nedenlerinden biri de buBreakpoint koymak da kolay değil; hatayı zenginleştirmek ya da işlemek yerine olduğu gibi yukarı taşımayı tercih ettiriyor
:='in tek bir statement içinde bildirim ve atama olduğunu sanıyordum; örneğin 5. satırındaerryeniden bildiriliyor ve yenierrmevcuterr'i gölgeliyor değil mi?Öyleyse yeni
errdeğişkeni kullanılmadığı içindeclared and not used: errile başarısız olması gerekir gibi geliyorYoksa değişken zaten varsa
:=normal atama gibi mi davranıyor?“Hatalarda stack trace olmaması, yardımcı fonksiyonun zenginleştirilmiş bir hata oluşturup döndürmesiyle çözülebilir” demek gerçeğe fazla iyimser bakmak
Stack trace olan diller bunu bedavaya verir, ama Go'da her seferinde uygulamanız gerekir
Siz her zaman ayrıntı ekleyen disiplinli bir geliştirici olabilirsiniz, ama ekipteki herkes aynı disipline sahip olmaz
Stack trace'in en iyi yanı, hataya giden çağrı yolunu vermesidir
Birden fazla yerden çağrılan bir method'da hata oluşursa, stack trace ile hangi yolun izlendiğini hemen anlarsınız
Yıllarca sysadmin/SRE benzeri işler yapıp çok sayıda sorunu çözdüm; stack trace varken kolay sorunlar, neden apaçık olduğu için 1-2 dakikada bitiyordu
Go'da biri hatayı zenginleştirmezse ya da aynı hata mesajını yeniden kullanırsa, kolay sorunlar bile dedektiflik işine dönüşüp daha uzun sürer