1 puan yazan GN⁺ 2025-06-04 | 1 yorum | WhatsApp'ta paylaş
  • 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

 
GN⁺ 2025-06-04
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.

    • Geri bildirimin temelini oluşturan taslak tasarımda C++, Rust ve Swift geçiyor; ancak bağlantısı verilen kapsamlı geri bildirim belgesinde Haskell/Scala/OCaml’de kullanılan do notasyonu, for-comprehension, monadic-let gibi yaklaşımları bulamadım.
      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.
    • Gerçekten zeki ve çok deneyimli insanlar o sayfayı yazıp yıllarca tartışmışken, Haskell tarzı çözüm olan Maybe/Either monadları ve bind operatörünü kullanan do notasyonunun hiçbir yerde görünmemesi şaşırtıcı.
      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.
    • Bunun cevabı zaten bir yerlerde vardır ama bunun neden özellikle Go’da zor bir problem olduğunu merak ediyorum.
      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.
    • Go eleştirilerinde sık görülen kalıp şu: Görece amatör olan insanlar, Go’yu yapanların programlama dillerini kendilerinden daha az bildiğini varsayıyor.
      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.
    • Artık düzenlemek için onay almak gerekiyorken buna hâlâ Wiki denmesi garip.
  • 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; .await mi olsun, /await mi 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.

    • “Tamamlanmış, kusursuz birkaç öneri var” diye bir şey yok.
    • Rust’ın komite usulü tasarım yüzünden okunması çirkin ve söz dizimi tutarsız bir dil olarak ün kazanmasının yolu tam da bu.
    • Programlama dili tasarlanmış bir sistemdir; bütün olarak anlamlı olmalıdır.
      Onay kutusu gereksinimlerini karşıladı diye öylece eklenen bir özellikler koleksiyonu değildir.
    • 25 yıl sonrasına hatırlatma kurmak isterim.
      Rust, C++ gibi karmakarışık hâle gelmiş olacak mı? Go, çıktığı zamanki gibi zamana direnen bir dil olarak kalacak mı?
    • “Go herkesin hemen yaşadığı tek bir problemi çözemiyor” demek tuhaf.
      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 != nil ifadesine o kadar duyarsızlaşmıştım ki beynim, o kalıbın orada olmaması gerektiği ihtimalini hiç değerlendirmedi
    Bu yüzden yaygın ifadeler için sözdizimsel şeker gerektiğini düşünüyorum. Çok yaygın if err != nil ile nadir if err == nil arasındaki fark daha belirgin olsaydı gerçekten yardımcı olurdu

    • if err == nil her yazdığımda göze çarpsın diye // inverted yorumunu ekliyorum
      Bunun 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
    • Elbette if fruit != "Apple" { ... } de aynı durumu yaratabilir
      Bunu 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
    • Bu, aksine sözdizimi değişikliğine karşı bir gerekçe olur
      Yaygın bir if err == nil { return ... } kalıbı oluşursa bu kez o kodun her yerine yayılmış olacak
      Mevcut çö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
    • Şeytanın avukatlığını yaparsak, IDE ve yazı tipi Go sözdizimi modunda yalnızca if err != nil ifadesini tek, küçük bir ligatür simgesi gibi vurgulayabilir ya da arka planda soluk gösterebilir
      Böylece if err == nil gibi tam olarak o dizgeden farklı biçimler tam tersine göze çarpar
    • İyi nokta. Editörde if err … { gibi katlanmış bir gösterimle de çözülebilir gibi görünüyor
  • Go'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 error kullanmak yerine daha iyi tiplendirilmiş ve numaralandırılabilir hata tipleri olmasını isterdim
    Ancak 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

    • Deneyimime göre hata işleme politikası çağırana devredilmelidir
      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
    • “Bir fonksiyon başarısız olursa o başarısızlığı işlemeniz gerekir” tam da Go'nun başarısız olduğu nokta
      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
    • borgo[1] sözdizimi olduğu gibi Go 2 dili olsa keşke. Hayal kurmak serbest
      [1]: https://borgo-lang.github.io/ | https://github.com/borgo-lang/borgo
    • Bu hızla Go2 hiç çıkmayacak bir fikir laboratuvarı gibi görünüyor
    • Neye kıyasla iyi olduğunu sormak isterim
      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

    • Üzücü bir hikâye. Verilen iki gerekçenin de Go hata işlemenin ne kadar kötü olduğuyla ilgisi yok; hata işlemeyi daha iyi yapmak bunları kötüleştirmez
      Aksine iyileştirme ihtimali yüksek
    • PHP bile hata seviyeleri ve çağrı noktasında hatayı bastıran @ operatörü sayesinde daha iyi hata işlemeye sahip
      bash'te de -e var
    • Ben de Go yaklaşımını seviyorum. Ne olup bittiğini daha kesin bileceksem daha fazla kod satırına razıyım
      Eskiden 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
    • Rust tarzı sum type hataları da birer değerdir
  • 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ı?

    • Go ile profesyonel olarak çalıştığım zamanın %90’ı, her hata dönüş dalını statement coverage ile kapsamak için test senaryolarını zorla uydurmakla geçiyor
      İstisnaları olan bir dilde olsaydı kimse bunu yapmazdı
    • Bu yazının hiçbir yerinde “ana sorun sözdiziminin fazla laf kalabalığı olması” iddiasında bulunulduğunu sanmıyorum
      Ö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 herhangi bir biçimde generics desteği sunmasının bile inanılmaz uzun sürdüğünü hatırlamak gerek
      Go’nun evrimi buzul kadar yavaş ve birçok kişi için bu bir hata değil, özellik
    • %100 katılıyorum. İkisi de Googler ama Go ekibinden bir kez daha hayal kırıklığına uğramak çok üzücü
      1. maddeye katılıyorum, ancak errcheck gibi geliştirme araçlarıyla bir ölçüde hafifletilebilir: https://github.com/kisielk/errcheck?tab=readme-ov-file
  • “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ğlenceli
    Go ekibinin tanımına göre istisnalar hataları otomatik işliyor sayılır. Elbette C++ dışındaki dillerde

    • İnsanların ekranı dolduran stack trace’lere bakıp bunların açık ve faydalı olduğunu söylemesi ilginç
      Ö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ür
    Buna Elixir’in with ifadesini ekleyince hata işlemeyi aşağıda toplayabilirsiniz; bu da okumayı çok daha iyi hale getirir
    Go da with clause’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 koyabilir

    • Mevcut kanıtlara bakılırsa Go’nun with ifadesini benimseme ihtimali hiç yok gibi görünüyor
      Go’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
    • Go’nun çoklu dönüş özelliğinin kendisi benim bakış açıma göre tuhaf
      Birden fazla dönüş tipine sahip bir fonksiyonla, sonucu değişkenlere atamak dışında yapabileceğiniz bir şey yok
    • Haskell kullanıcıları ve Rust hayranları sum type’ları kendi mallarıymış gibi görüyor; insanlar da onların yorumlarını ve yazılarını okuyup inandıktan sonra korkutucu Hindley-Milner tavşan deliğine düşmek istemedikleri için sum type’lardan uzak duruyor
      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üyorum
    Ama 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: err verir, ama ikinci dönüşümden sonra err kontrol edilmese bile y'nin varsayılan değeri 0 olduğu için sorun fark edilmeden gayet çalışabilir
    if err != nil { } gibi boş bırakılsa da derlenir ve çalışır; bir şeylerin yanlış olduğunu anlayamazsınız
    Dö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 zaman panici de mi yasaklayacağız?

    • Go'da sum type yok, bu yüzden Result'a sahip olamıyor
      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
    • Rust tarzını Go'ya koyarken tam olarak neyin eşdeğer biçim olacağı net değil
      Ö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 gizliyor
      Go'nun ternary operatörü kaldırıp her dalın ayrı satırda olduğu if deyimini seçmesinin nedenlerinden biri de bu
      Breakpoint 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ında err yeniden bildiriliyor ve yeni err mevcut err'i gölgeliyor değil mi?
      Öyleyse yeni err değişkeni kullanılmadığı için declared and not used: err ile başarısız olması gerekir gibi geliyor
      Yoksa 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