· kaynak Hacker News – Front Page (native)
Goose dili, heap'siz bellek modeliyle C++ ve güvenli Rust'ı geride bırakmayı iddia ediyor
Goose adlı yeni bir sistem dili, heap'i derleyici tarafından yönetilen veri yığınlarıyla değiştiriyor; elle optimize edilmiş C++ ve güvenli Rust karşısında benchmark kazançları raporlarken, hiçbir ek açıklama gerektirmeden bellek güvenliğini zorunlu kılıyor.
Goose adlı yeni bir sistem dili, C++ ve güvenli Rust'ı kendi oyunlarında yenmeyi iddia ediyor: daha hızlı, daha küçük ve bellek güvenli; allocatör yok, garbage collector yok, reference counting yok ve lifetime açıklaması yok. GitHub'da aardapel hesabı altında barındırılan proje, bu ay Hacker News ana sayfasına tek bir alışılmadık öncül sayesinde ulaştı: heap yok.
İddialar
Projenin README'sine göre, on altı benchmark boyunca Goose, idiomatik C++'ın 3,3 katı, elle optimize edilmiş C++'ın 1,16 katı ve en iyi güvenli Rust kodunun 1,12 katı hızla çalışıyor; bellek kullanımı ise sırasıyla 1,9 kat, 1,3 kat ve 1,2 kat daha az. README, bu kazanımların yapısal olduğunu, yani ince ayardan değil dilin kendisinin özelliklerinden geldiğini savunuyor ve Goose'un kaybettiği benchmark'ları da içerdiğini söylediği tam bir sonuç sayfasına bağlantı veriyor.
Tek bellek modeli: veri yığınları
Bir Goose programında yerel çağrı yığını (call stack), statik veri ve derleyicinin belirlediği sayıda veri yığını bulunur. Her veri yığını, bump pointer'lı büyük bir ayrılmış adres aralığıdır ve başka türde bellek yoktur. Her yığında en fazla bir yeniden boyutlandırılabilir değer canlıdır ve o değer her zaman en üstte durur; bu yüzden bir değeri büyütmek mevcut veriyi hiç taşımaz ve kapasite kontrolü yapmaz. Tüm bunları derleme zamanında kanıtlanır; runtime yalnızca bump pointer'ları takip eder. Serbest bırakma, kapsam çıkışında tek bir store işlemidir; dolayısıyla milyon elemanlı iç içe geçmiş bir yapıyı serbest bırakmak, ne kadar derin olursa olsun aynı tek store işlemine mal olur.
Değerler hiçbir zaman taşınmadığı için, büyüyen bir diziye olan referans, dizi yaşadığı sürece geçerli kalır. Bir eleman push etmek, az önce oluşturulan şeye bir referans döndürür ve README, C++ vector'lerinin ve Rust'ın Vec'inin reallocasyon yaptıkları için garanti edemediği bu özelliği, benchmark kazanımlarının önemli bir bölümüne atfediyor.
Sözdizimsiz güvenlik
Bellek güvenliği tek bir kurala dayanır: bir referans, hedefini sahip olan değişkenden daha uzun yaşayamaz ve hedefi asla yanlış tipte göremez. Her referans, sahibini adlandıran çıkarılmış (inferred) bir statik kök taşır ve fonksiyonlar kök başına özelleştirilir. README'ye göre bunun sonucu, lifetime sözdizimi olmayan, aliasing veya exclusivity kuralı olmayan ve unsafe kaçış kapısı olmayan bir güvenliktir. Denetleyici bir kodu reddettiğinde, çakışan lifetime'ın iki ucunu da adıyla belirtir.
Düz veri, ucuz enum'lar, offset bağlantıları
String'ler u8 dizileridir ve struct'lar satır içinde (inline) saklanan değişken boyutlu alanlar içerebilir; böylece bileşik değerler, iç işaretçi içermeyen tek parça bloklardır. README, Goose'ta sıfır ayırma (allocation) ile 29 bayt tutan bir sipariş kaydı örneği verir; C++ std::string ve std::vector ile 160 bayt ve bir ayırma, Rust'ın String ve Vec'i ile ise 153 bayt ve dört ayırma gerekir. Bunun bedeli, değişken boyutlu elemanlardan oluşan dizilerin sıralı olmasıdır: üzerlerinde gezinilebilir ama rastgele indekslenemez.
Enum'lar dilin tek dinamik polimorfizm aracıdır — kalıtım (inheritance) yok, vtable yok — ve her biri iki şekilde saklanabilir. Sabit mod, en büyük payload için yer ayırır; değişken mod her değere tam olarak kendi varyantının boyutunu verir. Bunu sınayan benchmark'ta README, bir Rust enum'ına kıyasla 4 kat daha az bellek ve 2 kat hız bildiriyor.
Nesneler arasındaki referanslar ayrıca bir, iki veya dört baytlık göreli offset olarak saklanabilir. Bu şekilde kurulan yapılar konumdan bağımsızdır (position independent); dolayısıyla kaydedilmiş bir veri yapısı fiilen kendi dosya formatıdır: kaydetmek bir yazmadır ve yüklemek, düşmanca baytları reddeden bir doğrulama geçişinin izlediği bir okumadır.
Paketin geri kalanı
Hatalar, statik olarak denetlenen bir return err ile istediği kadar stack frame'den geri döner; unwinder yok, Result tipi yok ve her çağrıda question-mark operatörü yok. Thread'ler hiçbir şey paylaşmaz: her worker kendi belleğiyle ayrı bir program olarak derlenir ve değerler tipli queue'lerden bir memcpy olarak geçer; bu da kilitleri, atomic'leri, memory ordering'leri ve veri yarışlarını (data race) dilden tamamen kaldırır. Değerler, çağrıların herhangi bir derinliğinden nihai hedefinde yerinde (in place) oluşturulur; dolayısıyla büyütülebilir bir diziyi değer olarak döndürmek ücretsizdir. Generic'ler tipsiz parametreler olarak ifade edilir ve fonksiyon değerleri, düz döngülere derlenen derleme zamanı varlıklarıdır.
Goose'un kendisi tek bir C dosyasına derlenir; böylece bir C derleyicisinin hedeflediği her platformda çalışabilir ve C'yi doğrudan extern fn üzerinden çağırabilir. Yerleşik bir TinyCC backend'i, bir programı ayrı bir derleme adımı olmadan süreç içinde (in-process) derleyip çalıştırır.
Neden önemli
Sistem programlamadaki yerleşik bilgi, bellek güvenliğinin bir maliyeti olduğudur: bir garbage collector, lifetime açıklamaları, runtime kontrolleri veya disiplinli elle yönetim. Goose'un bahsi, heap'i silmenin maliyeti de silmesidir — açıklama yükünü, reallocasyonla gelen geçersizlik hatalarını ve serialization adımını da tek seferde. Performans iddiaları projenin kendi benchmark setinden geliyor ve diller arası benchmark'lar meşhur şekilde tartışmaya açıktır; ama README, bazı sonuçların aleyhine olduğu konusunda en azından dürüst. Bir yapay olarak dil niş kalabilir; ama bir fikirler kümesi olarak — bump pointer'lı veri yığınları, işaretçisiz düz yerleşimler, offset tabanlı bağlantılar, denetlenmiş çok frame'li hata dönüşleri — C++ ve Rust'ın performans ve güvenlik tasarım alanının tamamını zaten doldurduğu varsayımına meydan okuyor.
- #programming-languages
- #memory-safety
- #systems-programming
- #benchmarks
- #compilers