1 puan yazan GN⁺ 2025-10-05 | 1 yorum | WhatsApp'ta paylaş
  • Ada ve Rust dilleriyle Advent of Code problemleri çözülürken ortaya çıkan farklar ve özellikler karşılaştırılıyor
  • Güvenlik ve güvenilirlik odağındaki bu iki dilin dil tasarımı ile gerçek program yazma biçimleri arasındaki farklar analiz ediliyor
  • Her dilin standart kütüphanesi, özelliklerin yerleşik olup olmaması, performans farkları, hata işleme tarzı gibi çeşitli açılardan ayrıştığı görülüyor
  • Modülerlik, generic'ler, döngüler, hata yönetimi gibi konularda gerçek kod örnekleriyle, yazım ve işletim sırasında karşılaşılan somut durumlar anlatılıyor
  • Statik tip belirtme yaklaşımı, dizi işleme ve hata işleme arayüzlerindeki farkların geliştirici deneyimini belirgin biçimde etkilediği vurgulanıyor

Giriş ve amaç

  • Advent of Code(kısaca AoC) problemlerini çözerken başlangıçta yalnızca Ada kullanılırken, 2023'ten itibaren çözümler Rust ve Modula-2 ile de yazılmaya başlanınca doğrudan karşılaştırma yapma imkânı doğdu
  • Mevcut Ada merkezli çözümler Rust'a taşınırken iki dilin yapısal farkları ve kendine özgü yaklaşımları doğrudan hissedildi
  • Amaç, kod güvenliği, güvenilirlik ve dil tasarımı açısından gerçek kullanım farklarını daha net ortaya koymak

Karşılaştırmada kullanılan dil sürümleri

  • Ada 2022 (gerektiğinde Spark 2014'ün bazı kurallarına da başvuruluyor)
  • Rust 2021 (ana karşılaştırmalar Rust 1.81.0 sürümü temel alınarak yapılıyor)

Hariç tutulan özellikler ve karşılaştırma ölçütleri

  • Her dilin öne çıkan özellikleri (=killer feature) metin içinde kısa yorumlarla anılıyor
  • Kişisel deneyim ve çözümlerin pratik gereksinimlerine bağlı olarak ele alınmayan bazı özellikler de var
  • Mümkün olduğunca öznel görüşler dışarıda bırakılarak temel özelliklere odaklanılıyor

Yazarın arka planı ve bakış açısı

  • Hem Ada hem Rust kullanımı, ana dili bu diller olmayan bir geliştirici perspektifinden; temelinde C/C++, Pascal, Modula-2 gibi 1980'ler dilleri deneyimi var
  • Bu nedenle kod stili modern/idiomatik yaklaşımlardan farklı olabilir
  • Uygulamalar her zaman en iyi çözüm olmayabilir; bazı durumlarda sezgisel ya da alışılmadık yöntemler seçilmiş olabilir

Ada ve Rust'ın konumlandırılması

  • Ada, bugün de son derece güvenli ve güvenilir sistem/gömülü geliştirme dili olarak varlığını sürdürüyor ve kod okunabilirliğine önem veriyor
  • Rust, bellek güvenliği ve sistem programlama gücüyle öne çıkıyor; Stack Overflow geliştirici anketlerinde yıllardır 'en sevilen dil' olarak gösteriliyor
  • Ada, genel amaçlı yüksek seviyeli bir dil olarak okuma ve bakım tarafında güçlü bir yelpaze sunuyor
  • Rust ise düşük seviyeli sistem programları geliştirmeye yöneliyor; açık bellek yönetimi ile hata/seçenek tipleri temelli güvenli programlama kültürü oluşturuyor

Güvenlik ve yapısal özelliklerin karşılaştırması

  • Ada

    • ISO standardı mevcut (katı ve ayrıntılı bir spesifikasyon)
    • Problemin niteliğine uygun tipleri (aralık, basamak sayısı vb.) tanımlamak kolay
    • Dizi indekslerinin sayısal olması şart değil
    • Spark adlı daha da katı bir spesifikasyon bulunuyor
  • Rust

    • Spesifikasyon daha çok resmi belgeler(Reference) ve derleyici etrafında şekilleniyor
    • Tip tanımları makine tiplerine dayanıyor (ör. f64, u32)
    • Dizi indeksleme doğal olarak yalnızca sayısal tiplerle yapılıyor

Özellikler / yerleşik destek tablosundan öne çıkanlar

  • Dizi sınır kontrolü, generic konteynerler, eşzamanlılık, etiketli döngüler, pattern matching desteği gibi alanlarda farklar bulunuyor
  • Ada, hata işleme için Exception(istisna) temelli bir yaklaşım kullanırken Rust, Result/Option tipleriyle dönüş değeri tabanlı bir yöntem izliyor
  • Rust; makrolar, pattern matching, fonksiyonel saflık desteği gibi konularda belirgin biçimde ayrışıyor
  • Ada, sözleşme tabanlı tasarım ve DBC(Design By Contract) derleme zamanı doğrulamasını Spark üzerinden destekliyor
  • Bellek güvenliği açısından Rust ve Spark bunu zorunlu kılarken, Ada null pointer kullanımına izin veriyor

Performans ve çalışma süresi karşılaştırması

  • Genel kanı, Rust'ın çalışma zamanında hızlı ama derleme hızında yavaş, Ada'nın ise tersine daha hızlı derlenip çalışma zamanında doğrulama kontrollerine göre biraz daha yavaş olabildiği yönünde
  • Benchmark sonuçlarında, Rust day24 probleminde f64 tipinin sınırları nedeniyle taşma yaşarken, Ada digits 18 gibi yüksek seviyeli tip tanımlarıyla uygun makine tipini otomatik seçip taşmadan kaçınarak güçlü performans gösterdi
  • Rust tarafında kararsız durumdaki f128 ya da harici kütüphaneler gerekirken, Ada yalnızca derleyici spesifikasyonuna uygun tip tanımıyla avantaj sağlayabiliyor

Dosya işleme ve hata yönetimi (Vaka İncelemesi 1)

Ada'da dosya işleme

  • Temelde Ada.Text_IO kullanılıyor
  • Dosya açma, satır satır okuma, istenen aralık ve konuma göre satır işleme gibi işler görece sezgisel biçimde yapılabiliyor
  • Hata durumunda, açık bir hata mesajından çok istisna fırlatılıyor ve fonksiyon imzasında hata olasılığı görünmüyor

Rust'ta dosya işleme

  • std::fs::File ve BufReader kullanılıyor
  • Dosya açılışı Result tipi döndürdüğü için hata ihtimali açıkça görülüyor
  • Karakterlere doğrudan indeksle erişim yok; mutlaka Iterator ile işlem yapmak gerekiyor
  • map, filter, collect, sum gibi fonksiyonel/yinelenebilir araçlar merkezde yer alıyor ve çeşitli makrolar da sunuluyor (ör. include_str!)
  • Dönüş tipinde hataların açıkça belirtilmesi sayesinde, hata yayılımı fonksiyon düzeyinde daha net hâle geliyor

Modülerlik ve generic'ler (Vaka İncelemesi 2)

Ada'nın modülerliği

  • Paket(package) tabanlı yapı sayesinde belirgin bir spesifikasyon(arayüz) ve gerçekleme ayrımı var
  • Modülerliği güçlendirmek için alt paketler ile use/rename sözdizimi birlikte kullanılarak okunabilirlik ayarlanabiliyor
  • Paketlerin generic desteği var: tipler, sabitler ve hatta alt paketlerin tamamı genelleştirilebiliyor

Rust'ın modülerliği

  • Modüller mod/crate sistemiyle düzenleniyor; spesifikasyon ve gerçekleme ayrımı dokümantasyon üreticileriyle büyük ölçüde otomatikleşiyor
  • pub/private erişim belirleyicileriyle bildirime dayalı erişim yetkisi veriliyor
  • use/as ile import ve yeniden adlandırma birlikte kullanılabiliyor
  • Yerleşik test desteği sayesinde test modülleri doğrudan koda yazılabiliyor, derlenebiliyor ve otomatik çalıştırılabiliyor

Generic'ler

  • Ada yalnızca paket/prosedür düzeyinde generic desteği sunuyor (tek başına tipe uygulanamıyor)
  • Rust'ta tiplerin kendisine generic uygulanabiliyor (template benzeri yapı)
  • Ada, tip aralığı gibi ek özellikleri range type, subtype gibi yapılarla açıkça ifade edebilirken, Rust tarafında örnek sabitler kullanılıyor

Enum tiplerinin karşılaştırılması (Vaka İncelemesi 3)

  • Ada, kısa ve sade bir bildirimle birlikte ayrık, sıralı ve döngü/indekslemede kullanılabilir tipleri otomatik olarak sağlıyor
  • Rust enum bildirimleri de benzer görünse de, pattern matching ve yineleme gibi kullanım biçimlerinde daha açık seçik ifadeler gerekiyor

Sonuç

  • Yüksek seviyeli spesifikasyon tipleri, doğrulanabilirlik ve çalışma zamanı kontrolleri gibi alanlarda Ada daha sıkı bir denetim sunuyor
  • Fonksiyonel programlama stili, makro programlama, derleyici destekli hata işleme gibi konularda Rust hem geliştirme kolaylığı hem de güvenlik açısından üstünlük gösteriyor
  • Gerçek problem çözümünde Ada, eski kodla uyumluluk ve bakım avantajları sunarken; Rust modern araç ekosistemi ile güvenlik/paralellik desteğinde öne çıkıyor

1 yorum

 
GN⁺ 2025-10-05
Hacker News görüşleri
  • Ada’da gerçekten çok iyi fikirler olmasına rağmen, bunların çoğunlukla yalnızca güvenliğin çok kritik olduğu alanlarda kullanılmış olması üzücü. Özellikle sayısal tiplerin değer aralığını kısıtlama özelliği, belirli hataları önlemede çok faydalı. Spark Ada’yı öğrenmek de, SIL 4’e (en sıkı yazılım güvenlik standardı) uygun yazılım geliştirmede kullanmak da kolaydı. Son birkaç on yılda yazılım sektörü “önce büyüme, sonra güvenilirlik” anlayışına kaydı, ama şimdi yeniden güvenli yazılım geliştirmeye dönüş hissediliyor. Bu süreçte biriken güvenlik derslerinin daha iyi dillere dönüşmesini umuyorum. Gerçekte ise iyi fikirler çoğu zaman az kullanılan dillerin içinde saklanıp kayboldu
    • Yazılım geliştirmede uzun zaman geçirince “tekerleği yeniden icat etmenin” ne kadar sık olduğunu fark ediyorsunuz. Ada ile Rust, güvenliği hedefleme açısından benziyor ama bunun tanımı ve kapsamı farklı. Rust çok odaklı bir biçimde önemli bir güvenlik türünü çok güçlü şekilde hedefliyor; Ada ise daha geniş ve daha somut bir güvenlik tanımına sahip. 90’ların başında Ada öğrendiğimde en yaygın eleştiri, dilin fazla büyük ve karmaşık olduğu ve geliştirme hızını düşürdüğüydü (o dönemde Ada 83 onaylı bir derleyici kişi başına bugünün parasıyla yaklaşık 20 bin dolardı). Ama zaman değişti ve insanlar Rust gibi büyük ve karmaşık bir dilin gerçekten güvenli eşzamanlı programlama için gerekli olduğunu kabul etmeye başladı
    • Nim de Ada ve Modula’dan ilham alarak tiplerin değer aralığını sınırlayan subrange desteği sunuyor
      type
        Age = range[0..200]
      
      let ageWorks = 200.Age
      let ageFails = 201.Age
      
      Derleme sırasında 201’in Age tipine dönüştürülemeyeceğini söyleyen bir hata alırsınız
      Nim Subranges açıklama bağlantısı
    • Ada (GNAT özelinde) derleme zamanında fiziksel birim/boyut analizi, yani birim kontrolü, destekliyor. Mühendislikte son derece pratik; diğer dillerin bu kadar önemli bir özelliği neden sadece üçüncü taraf kütüphanelerle sunduğunu merak ediyorum
      İlgili belge
    • C++’ta da değer aralığı kısıtlı sayısal tipleri kodla kolayca oluşturabilirsiniz (standart kütüphanede yok ama kendiniz yazması çok kolay). Bazı güvenlik kontrolleri çalışma zamanında değil derleme zamanında yapılabilir. Keşke tüm diller bunu standart olarak desteklese
    • Ada’da en çok sevdiğim şeylerden biri nesne yönelimli programlamaya dair net yaklaşımıydı. Çoğu dil OOP kavramlarını “sınıf” denen tek bir pakete doldururken, Ada mesajlaşma, dinamik dispatch, alt tipleme, generics gibi özellikleri tek tek seçip kullanmanıza izin veriyor. Bu özelliklerin birbiriyle zarif biçimde birleşmesi çok hoşuma gitmişti
  • Yazar, Ada’da resmi bir spesifikasyon olup Rust’ta olmaması gibi farklardan söz ediyor ama pratikte kullanıcı açısından bundan daha önemli olan şey dilin benimsenmesi ve ekosistemi: tooling, kütüphaneler, topluluk. Ada havacılık/uzay ve güvenlik kritik alanlarda başarılı oldu, AoC ya da gömülü düşük seviye işler için de uygun olabilir; ama gerçek projelerde (dağıtık sistemler, OS bileşenleri vb.) veri formatları, protokoller, IDE desteği ve ekip arkadaşlarıyla işbirliği gibi unsurlar daha ağır basıyor. Sonuçta bir dili ilk seçerken belirleyici olan çoğu zaman bu çevresel faktörler
    • Yakın zamanda Rust da Ferrocene üzerinden Ada tarzı spesifikasyon yaklaşımından esinlenen bir spec belgesini bağışladı. Açık olduğu için bakılabilir
      Rust spec
    • Rust da Ada da katı anlamda “biçimsel/formal spesifikasyon” konusunda zayıf. Spark Ada’da bile dil anlambilimine dair varsayımlar var, ama bunlar da tamamen resmi ve makinece okunabilir bir biçimde değil
    • Uçak kontrol yazılımı geliştiricileri muhtemelen “gerçek dünyada önemli olmayan bir iş içinse evet, bizim süreç fazla ağır kaçıyor” diyecektir. Güvenlik kritik alanlarda Ada gibi katı diller ve süreçler zaten standarttır
  • Ada’nın, Rust’a göre tip özellikleri daha sınırlı olsa da, kod okunabilirliğinde çoğu zaman daha iyi olabildiği dikkat çekiciydi. Karşılaştırmada derleyici hızı konusu eksikti; Ada’nın karmaşık bir dil gibi görünmesi geçmişte kalmış olabilir, bugün Rust’la kıyaslandığında durum o kadar da öyle olmayabilir. Bu yazı beni Ada ile gerçek bir proje denemek istemeye yöneltti
    • “Tiplerle ilgili dezavantajlar” derken tam olarak ne kastedildiğini merak ediyorum. Benim deneyimimde Ada’nın tip sistemi inanılmaz derecede ifade gücü yüksek. Kullanıcı tanımlı değer aralığı tipleri, keyfi enumlarla indekslenebilen diziler, tipe özgü operatör tanımları, derleme/çalışma zamanı kontrolleri, önkoşullar/sonkoşullar gibi birçok ek özelliği tipe bağlayabiliyorsunuz. Discriminated record’lar, struct representation clause’lar da var. Bence bu bir zayıflık değil, güçlü bir özellik
  • Ada ile Rust’ın string farkı hakkında konuşmak istiyorum. Ada 1980’lerin başında tasarlandığında char dizilerini “string” olarak ele aldı; bu yüzden düz byte dizisi gibi indekslemek kolay. Rust ise baştan Unicode bilinciyle tasarlandı, dolayısıyla Rust string’i UTF-8 kodlu, yani gerçekten “metin”. Bu yüzden Ada’da dizi gibi rastgele indeksleme mümkünken, Rust’ta string kavramı farklı; isterseniz bunu byte dizisine çevirmek de mümkün
    • Ada’nın yerleşik Unicode string’leri genelde UTF-32 dizileridir. Rust’ın aksine doğrudan UTF-8 literal sağlamaz; 8/16/32 bit dizilerden dönüştürmeniz gerekir
    • Rust string’lerinde de indeksleme yapılabilir. Ancak Rust string’i normal bir dizi gibi ele almak yerine daha çok sub-string slice kullanır. Bir karakterin ortasından kesmeye çalışan bir indeksleme yaparsanız panic oluşur (Unicode kodlama sınırlarını ihlal ettiğiniz için). AoC gibi her zaman ASCII kullanıyorsanız [u8] ya da str::as_bytes ile byte slice kullanmak daha doğru
  • Yazarın Rust’ın “eşzamanlı programlamayı varsayılan olarak desteklemediği” yönündeki sözü bana garip geldi. Rust’ta thread desteği dilde yerleşik ve çoğu durumda async’ten de kullanımı daha kolay. Ancak çok sayıda thread gerekip kaynak sınırına dayandığınız durumlarda sorun çıkabilir; bunun dışında çoğu yazılım için built-in thread’ler yeterli
    • (Rust kullanmayan biri olarak gerçekten merak ediyorum) Rust’ta thread ve async tarafında iptal/cancel işlemleri nasıl farklı işliyor, diğer dillerdeki async’ten farkı ne? C++, Python ve C#’ta async iptal yönetimi thread’lere göre çok daha iyiydi. Rust’ta bu iptal/yarıda kesme yönetimi exception ile ele alınmadığı için hatta biraz daha zor deniyor; gerçek iş deneyimi olanların görüşünü merak ediyorum. Ada’da bu tür iptal yönetimi nasıl, onu da duymak isterim
    • Tokio gibi work-stealing scheduler’ların, sadece birden çok thread çalıştırmaya göre pratikte ne kadar daha hızlı olduğu ve eşik noktasının nerede başladığı merak konusu. Küçükken hızlı olan basit bir dizi yapısının (ör. VecMap) belli bir eleman sayısından sonra başka veri yapıları tarafından geçilmesine benzer bir durum gibi geliyor. Work-stealing’in ne zaman gerçekten avantaj sağladığını merak ediyorum
    • Pratikte Async kullanmanın başlıca sebebi, kullandığınız üçüncü taraf crate’in Async olması. (Örn. Reqwest, Tokio gerektiriyor.) Daha yüksek seviyeli uygulama geliştirmede yalnızca non-Async çizgisinde kalmaya çalışırsanız sonunda sınıra dayanıyorsunuz
    • Platformun thread desteğinin zayıf olduğu ortamlarda (WASM, embedded vb.) Async aslında daha uygun olabilir. Yüz binlerce kişinin aynı anda bir bloga girmesi çok gerçekçi değil; Async ihtiyacını hep bu tür örneklerle savunmak bana biraz abartılı geliyor
  • Ada için açık kaynak bir derleyici de olması ilgimi çekti. Eskiden hepsinin sadece kapalı kaynak/özel derleyiciler olduğunu sandığım için Ada’yla hiç ilgilenmemiştim; bir kez daha bakmam gerekecek
    • GNAT derleyicisi 30 yıldan uzun süredir var; bir dönem GPL runtime exception olmadığı için derlenmiş çıktıların da GPL olması gerektiği gibi bir yanlış anlama vardı, ama artık bu konu çözüldü
    • GNAT, 90’lardan beri GCC tabanlı geliştiriliyor ve bazı üniversitelerde gerçek zamanlı programlama gibi uygulamalı derslerde doğrudan kullanıldı. Ben de Ada’yı programlamaya giriş dili olarak kullanmaya çalışmış, ama kısa süre sonra Pascal ve C++’a geçmiştim
  • 3D baskı alanında ilgimi çeken projelerden biri de yakın zamanda Prunt adlı yazıcı kontrol kartı ve firmware projesiydi. Firmware’i Ada ile geliştiriyorlar; epey sıra dışı ama kavramsal olarak da oldukça uygun bir tercih
    Prunt ana sayfası
    Prunt GitHub
    • Neden böyle bir seçim yaptıklarını anlattıkları bir yazı da var
      İlgili HN yorumu
  • Case Study 2’nin sonunda “istemcinin SIDE_LENGTH’i bilmesi gerekiyorsa, bunu döndüren bir fonksiyon ekleyin” denmiş; ama fonksiyon yerine doğrudan pub const SIDE_LENGTH: usize = ROW_LENGTH; gibi bir sabit tanımı kullanmak daha doğrudan olur
  • Her iki dilin de stack merkezli programlamayı teşvik ettiği iddiasına katılmıyorum. Ada, aksine, statik tahsisi güçlü biçimde teşvik eder
  • Ada’da dizi indekslerinin keyfi tipler olabilmesinin büyük bir avantaj gibi sunulması ilginçti. Neredeyse tüm diller standart kütüphanede dictionary/hashmap sunuyor; Rust’ta da iki tane var
    • Burada kastedilen şey dilin yerleşik dizi yapısı. Örneğin Ada’da “eggs” adlı bir dizinin indeksi BirdSpecies tipi ise eggs[Robin], eggs[Seagull] anlamlıdır ama eggs[5] geçerli değildir. Rust’ta da isterseniz kendi veri yapınızı kurup (örneğin Index<BirdSpecies> uygulayarak) eggs[Robin] yapabilirsiniz, ama eggs[5] hata verir. Yalnız Rust bunu doğrudan dil seviyesinde “dizi” olarak sunmaz. Ada’daki gibi “kullanıcı tanımlı tiplerin bir alt kümesi olan tamsayı tipleri” tanımlanabildiğinde bu indeksleme gerçekten değer kazanıyor. Rust’ta henüz saf kullanıcı tanımlı tiplerle aralık kısıtlı integer’lar oluşturulamıyor (yalnızca dahili olarak NonZeroI16 gibi tipler var). Rust bunu da desteklese harika olurdu
    • Ada’da da hashmap ve set yapıları standart olarak var. Ada containers standardı (A.18 bölümüne bakın). Dizi indeks tipi olarak tipik “ardışık değer” aralıklarının (ör. 0..N-1) kullanılabilmesi, yoğun map’lerde veya bitişik belleğe erişimin önemli olduğu durumlarda dictionary’den çok daha hızlı ve cache açısından daha verimli olabilir
    • Ada’daki dizi indeks tipi kısıtlaması (subtype), dictionary ile yapısal olarak tamamen farklı bir kavram. Dil, dizi indeksinde kullanılabilecek değer türlerini doğrudan sınırlayabiliyor