30 puan yazan GN⁺ 2025-12-06 | 1 yorum | WhatsApp'ta paylaş
  • Üç dilin felsefe ve değer anlayışlarındaki farklar odağa alınarak, her birinin hangi sorunları çözmeye çalıştığı karşılaştırılıyor
  • Go, sadelik ve istikrarı önceleyen; özellikleri minimumda tutarak iş birliği ve bakımı kolaylaştıran bir dil olarak açıklanıyor
  • Rust, güvenlik ve performansı aynı anda hedefliyor; karmaşık tür sistemi ve trait yapısıyla bellek güvenliğini garanti ediyor
  • Zig, manuel bellek yönetimi ve veri odaklı tasarım yoluyla geliştiriciye tam kontrol veren deneysel bir dil olarak tasvir ediliyor
  • Üç dilin birbirine zıt yaklaşımları, programlama dillerinin hayata geçirdiği değer sistemlerini ortaya koyuyor; seçim ölçütü de geliştiricinin hangi felsefeye yakınlık duyduğu oluyor

Dil karşılaştırısına bakış

  • Yazar, işte kullandığı dillerden ziyade, yeni dil denemeleri üzerinden her dilin değer sistemini anlamaya çalışıyor
  • Yalnızca özellik listelerini kıyaslamak yerine, dilin hangi ödünleşimleri seçtiğinin önemli olduğunu vurguluyor
  • Go, Rust ve Zig işlevsel olarak birçok ortak noktaya sahip olsa da, tasarımcılarının öncelik verdiği değerler farklı
  • Her dilin felsefesini kavrayarak, hangi ortam ve amaçlar için uygun olduğuna karar vermek mümkün

Go — sadelik ve iş birliği odaklı dil

  • Go, minimalizmiyle ayrışıyor ve “tüm dili kafanda tutabilirsin” özelliğine sahip
    • Generics ancak 12 yıl sonra eklendi; tagged union ya da hata işleme için sözdizimsel şeker gibi özellikler hâlâ yok
    Reklam
  • Yeni özellik ekleme konusunda çok temkinli; bu yüzden boilerplate kod fazla olsa da dilin istikrarı ve okunabilirliği yüksek
  • Go’daki slice, Rust’ın Vec<T> ya da Zig’in ArrayList işlevlerini kapsıyor; bellek konumunu çalışma zamanında sistem otomatik yönetiyor
  • C++’ın karmaşıklığı ve yavaş derleme sürelerine duyulan tepkiyle yola çıkıp, basit ve hızlı derleme hedefiyle tasarlanmış
  • Kurumsal ortamlarda iş birliği verimliliğini önemser; karmaşık özelliklerden çok açık kodu ve tutarlılığı öne koyar

Rust — karmaşık ama güçlü güvenlik ve performans

  • Rust, “sıfır maliyetli soyutlama” söylemini benimseyen, çok sayıda kavramı bir araya getiren maksimalist bir dil
  • Öğrenmesinin zor olmasının nedeni kavramsal yoğunluğunun yüksek olması; karmaşık bir tür sistemi ve trait yapısı bulunuyor
  • Rust’ın temel hedefi, performans ile bellek güvenliğini birlikte sağlamak
    • UB (Undefined Behavior) önlemek için derleme zamanında doğrulama yapıyor
    • Hatalı pointer referansları veya çift serbest bırakma gibi durumların yol açtığı öngörülemez davranışları engelliyor
  • Derleyicinin kodun çalışma zamanı davranışını anlayabilmesi için geliştiricinin türleri ve trait’leri açıkça tanımlaması gerekiyor
  • Bu yapı sayesinde başkalarının koduna duyulan güven artıyor ve kütüphane ekosistemi canlı kalıyor

Zig — tam kontrol ve veri odaklı tasarım

  • Zig, üç dil arasında en yeni dil; 0.14 sürüm aşamasında ve standart kütüphane belgeleri neredeyse yok
  • Manuel bellek yönetimi benimsiyor; geliştiricinin doğrudan alloc() çağırması ve allocator seçmesi gerekiyor
  • Rust veya Go’dan farklı olarak, global değişken oluşturmak kolay; çalışma zamanında “illegal behavior” tespit edildiğinde program durduruluyor
    • Derleme sırasında seçilebilen 4 farklı release modu ile performans ve güvenlik dengesi ayarlanabiliyor
    Reklam
  • Nesne yönelimli programlama (OOP) özellikleri bilinçli olarak dışarıda bırakılmış
    • private alanlar veya dynamic dispatch yok; std.mem.Allocator bile arayüz olarak uygulanmıyor
    • Bunun yerine veri odaklı tasarım (data-oriented design) yaklaşımı benimseniyor
  • Bellek yönetiminde de RAII tarzı ayrıntılı nesne bazlı yönetim yerine, büyük bellek bloklarının periyodik olarak ayrılıp serbest bırakıldığı bir yapı öneriliyor
  • Zig, özgür ve karşı-kültürel eğilimleri olan bir dil gibi betimleniyor; OOP düşüncesini ayıklayıp geliştirici odaklı kontrolü en üst düzeye çıkarıyor
  • Ekip şu anda tüm bağımlılıkları yeniden yazma çalışmalarına odaklanmış durumda; kararlı sürüm (1.0) içinse henüz bir tarih yok

Sonuç — dillerin ortaya koyduğu değer farkları

  • Go’nun merkezinde iş birliği ve sadelik, Rust’ın merkezinde güvenlik ve performans, Zig’in merkezinde ise özgürlük ve kontrol var
  • Üç dil arasındaki fark, basit bir özellik karşılaştırmasından çok, yazılım geliştirmeye dair felsefi bir tercihi yansıtıyor
  • Geliştiriciler dili, hangi değerlere yakınlık duyduklarına göre seçiyor

1 yorum

 
GN⁺ 2025-12-06
Hacker News görüşü
  • Rust'ta mutable global variable oluşturmak zor değil
    Sadece unsafe ya da senkronizasyon sağlayan akıllı pointer'lar kullanmak gerekiyor
    Çünkü Rust varsayılan olarak re-entrant ve derleme zamanında thread güvenliğini garanti ediyor
    Eğer statik thread güvenliğini önemsemiyorsanız, Zig ya da C'deki kadar kolay yapılabilir
    Fark şu ki Rust, kodun çalışma zamanı davranışı hakkında daha fazla garanti aracı sunuyor

    • Rust'ı uzun yıllar kullanmış biri olarak, mutable global variable'ın “yapılabiliyor olması, yapılması gerektiği anlamına gelmez” sözünün tipik bir örneği olduğunu düşünüyorum
      Başka dillere dönüp bunların bu kadar rahat kullanıldığını görünce, güvenlik açısından delilik gibi geliyor
    • “trivial, sadece ~ gerekiyor” tarzı ifadeleri C++, Perl ve Haskell için de duymuştum
      Ama bu tür “basit işler” birikince hiç de basit kalmıyor
      Rust bu çizgiyi zaten geçti ve artık kesinlikle trivial değil
    • Rust derleyicisinin thread'ler arası race condition durumlarını derleme zamanında yakalayıp yakalamadığını merak ediyorum
      Eğer öyleyse C'den daha cazip görünüyor
      İki değişkenin her zaman birlikte kilitlenmesi gereken durumlarda bunun nasıl ele alındığını da bilmek isterim
    • Ben bir dil tasarlasaydım mutable global variable'ı tamamen yasaklardım
      Debug ederken dönüp dolaşıp sorunun kaynağı hep orası çıkıyordu
  • Rust'ın kavram yoğunluğunu eleştiren yazı için, pratikte bunların sadece %5'ini bilmenin bile üretken olmak için yeterli olduğunu düşünüyorum
    12 yıldan uzun süredir Rust kullanıyorum ama #[fundamental] gibi bir şeye bir kez bile ihtiyaç duymadım
    Rust'ta arena allocation yapılabiliyor ve allocator kavramı da var
    Sadece bir varsayılan allocator bulunuyor ve genelde Box::new gibi açık heap allocation kullanılıyor
    Mutable global, static FOO: Mutex<T> = Mutex::new(...) gibi tanımlanabiliyor ve bellek güvenliği için mutex gerekiyor
    Rust'ın type system'i yalnızca bellek güvenliğini değil, kodun anlamsal güvenliğini de garanti edecek şekilde tasarlanmış

    • Ama başka geliştiriciler farklı %5–10'luk kavramları kullanabildiği için, birlikte çalışırken sonuçta daha fazla kavram öğrenmek gerekiyor
      C'de bu kadar karmaşıklık yok
      Karmaşıklık sonuçta önemli bir mesele
    • “Rust da arena allocation yapabiliyor” demek doğru ama Rust/Go kodlarının çoğu varsayılan yol olarak küçük boyutlu çok sayıda allocation kullanıyor
      Mesele sadece mümkün olup olmaması değil, temel programlama tarzı farkı
    • Rust'ta allocator bir type ise, m:n thread modelinde her istek için ayrı bir arena verilip verilemeyeceğini merak ediyorum
    • Rust'taki allocator'ın global olup olmadığını, tüm heap allocation'ların aynı allocator'ı kullanıp kullanmadığını soruyor
    • Casey Muratori'nin batch allocation videosundan söz ederek, bazı geliştiricilerin bunu yanlış anlayıp Rust'ın RAII yaklaşımını eleştirdiğini belirtiyor
      Zig Software Foundation'ın da Asahi Lina'nın Rust hakkındaki sözlerini yanlış aktardığı bir örnek olmuştu
      Zig'in başka dilleri küçümseyen pazarlama tavrı pek hoşuma gitmiyor
  • Zig'i sevmemin nedeni, bellek tükenmesini zarif biçimde ele alabilen bir dil olması
    Tüm allocation'ların başarısız olabileceği varsayılıyor ve bunun açıkça ele alınması gerekiyor
    Stack alanını da sihirli biçimde yönetmiyor; derleyici çağrı grafiğini analiz ederek azami boyutu tahmin ediyor
    Gömülü sistemlerde bu tür kaynak odaklı tasarım şart

    • Ama Linux gibi overcommit kullanan işletim sistemlerinde gerçekte allocation hatası oluşmuyor
      Bu, dil düzeyindeki işlemlerle çözülebilecek bir şey değil
    • Zig'in neden var olması gerektiği sorulacaksa, Rust zaten varken bunu sormak yerine “C varken neden Zig var?” diye sorardım
      Sonuçta yine manuel bellek yönetimi gibi aynı sorunla uğraşıyor
      O halde bence bir GC dili kullanmak daha mantıklı
    • Zig'de özyineleme ya da function pointer çağrıları olduğunda stack boyutu çıkarımının nasıl çalıştığını merak ediyorum
    • Zig ilk örnek değil; 1958'deki JOVIAL'dan beri gelen sistem dili tarihine bakmak gerekiyor
    • Rust'ta da pre-allocation iyi şekilde yapılabiliyor
      Ancak Rust'ın standart kütüphanesi OOM durumunda panic kullandığı için, gömülü geliştirmeyi destekleyen ayrı bir no-std ekosistemi bulunuyor
  • Go'nun slice yapısı Rust'taki Vec<T> ile aynı değil
    append() yeni bir slice döndürür; mevcut belleği paylaşabilir de paylaşmayabilir de
    Belleği küçültmenin bir yolu yoktur ve sadece append(s, ...) yazarsanız yeni slice'ı görmezden gelmiş olursunuz
    Go'nun tavrı “dediğimi yap”, Rust'ın tavrı ise “dediğimi yapıp yapmadığını doğrula” gibidir
    Yani Go sadelik uğruna hatalara izin verirken, Rust daha karmaşık olmayı göze alıp hataları azaltma yönünü seçiyor

    • Aslında bellek slices.Clip ile küçültülebilir
      Ayrıca sadece append(s, ...) yazmak derleme hatası verdiği için, orijinal metin biraz isabetsiz bir iddia içeriyor
      Go, özellik eklerken karmaşıklığın artmasını dikkatle tartan bir dil
    • “append(s, …)” zaten derlenmediği için yeni başlayan biri böyle bir hata yapamaz diye düşünüyorum
    • Go'ya generics gelmesine rağmen List[T] gibi type'ların yaygınlaşmaması ilginç
      Muhtemelen growable list'leri doğrudan etrafta taşımaya çok sık ihtiyaç duyulmuyor
    • Go'nun spec ve belgelerinde çoğu foot gun açık biçimde yazıyor
      İnsanlar çoğu zaman sadece dokümantasyonu okumayıp sonra şaşırıyor
  • C/C++'taki UB (Undefined Behavior) durumlarını çalışma zamanı kontrolleriyle yakalamanın pratikte zor olduğunu düşünüyorum
    Android de sanitizer'ları her commit'te uyguladı ama ancak Rust'a geçtikten sonra exploit sayısı azaldı

    • Android ve sanitizer iddiası için bir kaynak istiyor
  • Diller arası karşılaştırma yazısının her dilin güçlü ve zayıf yanlarını dürüstçe ele alması hoşuma gitti
    Sadece Raku'nun anılmaması biraz üzücüydü
    Bana göre C–Zig–C++–Rust–Go düşük seviyeli dillerin bir sürekliliğini oluşturuyorsa, yüksek seviyede de Julia–R–Python–Lua–JS–PHP–Raku–WL diye bir çizgi var

    • WL'nin ne olduğunu soruyor
    • Raku, ifade gücü yüksek genel amaçlı bir dil; çoklu dispatch, roles, kademeli tipleme, lazy evaluation ve güçlü bir regex sistemini yerleşik sunuyor
      Sözdizimi tanımını dil düzeyinde desteklediği için DSL yazmak ya da log parsing yapmak kolay
      VM tabanlı olduğundan performansı düşük ama problemin yapısını doğrudan ifade etmek için uygun
      Perl'in halefi olarak esnek ama tutarlı bir dil olmayı hedefliyor
  • Rust'ta bir fonksiyon pointer döndürdüğünde heap allocation'ın otomatik yapıldığını sanmak bir yanlış anlama
    Yerel değişkenler stack'te bulunur ve dönüşte yok olur, dolayısıyla pointer geçersiz hale gelir
    Rust güvenli modda pointer dereference etmeye izin vermez; unsafe modda ise geçerliliği garanti etme sorumluluğu geliştiriciye aittir
    Muhtemelen Box::new kullanımını “örtük allocation” ile karıştırmış

    • Go'nun escape analysis yaklaşımını Rust'ın açık heap allocation modeliyle karıştırmak anlaşılması zor bir hata
      Ya kavramlar yanlış anlaşılmış ya da kasıtlı olarak yanıltıcı bir anlatım var gibi görünüyor
  • Go'nun en büyük artısı basit concurrency modeli
    goroutine sayesinde paralel kod yazmak kolaylaşıyor

    • Go'nun güçlü yanlarından biri de kod tutarlılığı sayesinde büyük kod tabanlarında gezinmenin kolay olması
      Interface implementasyonlarını bulmak zor olabiliyor ama okunabilirlik yüksek olduğu için ekip çalışmasına uygun
    • Rob Pike'ın “Concurrency is not Parallelism” konuşması, Go'nun concurrency felsefesini iyi anlatıyor
      colored function yok ve channel tabanlı iletişim basit olduğu için doğru concurrency kodunu hızlı yazmak mümkün
    • Ama bence Structured Concurrency daha kolay bir model
      İlgili yazı: Structured Concurrency or Go Statement Considered Harmful
    • Zig'in yeni std.Io arayüzü Go'nun concurrency modeline benziyor
      go anahtar sözcüğü std.Io.async, channel'lar std.Io.Queue, select ise std.Io.select karşılığına sahip
    • Erlang geliştiricileri, Go'nun concurrency modelinin en kolay model olduğu iddiasına katılmazdı
  • Benim istediğim şey, Go'nun sadeliğini Rust'ın result/error/enum işleme biçimi ve daha iyi generics ile birleştiren bir dil

    • Ben de katılıyorum. GC'li ama daha güçlü bir type system'e sahip native bir dil için piyasada ciddi talep var
      OCaml, D, Swift, Nim, Crystal gibi dillere baktık ama hâlâ pazarı domine eden bir örnek çıkmadı
    • Modern OCaml'ın çok güçlü bir concurrency modeli olduğunu ve performansının da Go ile yarışabildiğini duydum
    • Borgo dili böyle bir denemeydi ama durduruldu
      Onun yerine Gleam'e bakılabilir
    • Go'nun error proposal'ı ilginçti
      Bu tür tekrarlayan sorunları çözebilecek bir iyileştirme gelmesini umuyorum
      Generics ise muhtemelen hâlâ zor bir mesele olmaya devam edecek
    • En yakın alternatif muhtemelen C#, ama o da hâlâ OOP merkezli bir dil
  • Yazının genel tonu, yeni bir geliştiricinin heyecanını ve merakını hissettirdiği için hoşuma gitti
    Go'da generics'in olmaması basit bir minimalizm değil, trade-off'lar üzerine düşünülmüş bir kararın sonucu gibi görünüyor
    Rust'taki lifetime birçok kişi için en büyük engeldi ve dilin yenilikçiliği de mevcut kavramların birleşiminde yatıyor
    Zig'in manuel bellek yönetimi OOP'yi dışlamaktan çok Data-Oriented Design (DOD) felsefesine dayanıyor
    İlgili konuşma: Andrew'un DOD sunumu

    • Russ Cox'un 2009 tarihli “The Generic Dilemma” yazısında ortaya koyduğu gibi,
      esas soru “yavaş programcı, yavaş derleyici, yavaş çalışma zamanı” seçeneklerinden hangisinin seçileceğiydi
      Go ekibi sonunda bunu tatmin edici şekilde çözen bir uzlaşma noktası bulmuş görünüyor