1 puan yazan GN⁺ 2025-01-08 | 1 yorum | WhatsApp'ta paylaş
  • Zig’in derleme zamanı (comptime) metaprogramlaması, çalışma zamanı kodu gibi okunurken; yapı alanlarını toplama gibi tekrarlı kodları, elle yazılmış bir C fonksiyonu kadar verimli çalıştırılabilir koda dönüştürebilir
  • Ayrı bir generic söz dizimi yerine comptime T: type ve anytype kullanarak generic programlama yapması, Zig comptime’ın başlıca kullanım alanıdır
  • Çalışma zamanı, comptime ve derleme sistemi aynı Zig dilini paylaştığı için, Fizz Buzz gibi bir fonksiyon da derleme sırasında çalıştırılıp önceden hesaplanmış bir diziye dönüştürülebilir
  • Derleyici mümkün olan kısımları önce değerlendirir; yalnızca çalışma zamanı değerlerine ihtiyaç duyan kısımları, daha sonra makine koduna dönüşecek çıktı bytecode’u olarak bırakır
  • Zig comptime, metinsel kod üretimine benzer sorunları çözebilir; ancak C makroları gibi anahtar sözcükleri keyfi biçimde ikame etmediğinden kod okuma ve hata ayıklama yükünü azaltır

Zig comptime’ı okuma bakışı

  • Zig’de comptime bir metaprogramlama özelliğidir; ancak nihai davranışı okurken derleme zamanı ile çalışma zamanı ayrımını çok fazla düşünmek gerekmez
  • zig zenin üçüncü maddesi olan “Favor reading code over writing code” önemli bir ölçüttür
    • Makro veya kod üretimi tabanlı metaprogramlama, özgün kod ve genişletilmiş kod diye iki katman oluşturabilir
    • Bu dolaylı katmanlar kod okumayı, hata ayıklamayı ve davranışı değiştirmeyi zorlaştırır
  • [3]i64 = .{1,2,3} dizisinin toplamını hesaplayan çalışma zamanı kodu ile MyStruct yapısının a, b, c alanlarını toplayan comptime kodu yan yana karşılaştırılır
    • inline for (comptime std.meta.fieldNames(MyStruct)) ile alan adları üzerinde dolaşılır
    • Derleme zamanında bilinen alan adını kullanarak alana erişmek için @field(my_struct, field_name) kullanılır
  • Yapı alanlarını toplama örneği çalışma zamanı reflection’ı gibi görünür; ancak yürütülebilir dosyada, ilgili yapı tipi için toplama fonksiyonu elle yazılmış gibi verimli kod kalır
  • Örnekteki dönüşüm süreci Zig uygulamasını birebir yeniden üretmekten çok kavramsal bir açıklamaya yakındır
  • Zig çekirdek ekibi, comptime ve çalışma zamanının karıştığı kodu örnekteki gibi adım adım çalıştırabilecek bir debugger üzerinde çalışıyor

Generic’leri comptime ile işleme

  • Zig’de ayrı bir generic özelliği yoktur
  • Bir tipi generic yapmak için, tip alan bir fonksiyonun tip döndürecek şekilde yazılması gerekir
    • Örnek: pub fn GenericMyStruct(comptime T: type) type
    • Döndürülen structın a, b, c alanlarının hepsi T tipini kullanır
  • Generic fonksiyonlar da aynı yöntemle yazılabilir
    • Örnek: fn quadratic(comptime T: type, a: T, b: T, c: T, x: T) T
    • quadratic(f32, ...) ve quadratic(i64, ...) gibi tip argümanı açıkça belirtilebilir
  • Argüman tipi fonksiyon imzasının başka bölümleri için önemli değilse özel tip anytype ile çıkarım yapılabilir
  • Bu yöntem tek başına comptime’ın tamamını açıklamaya yetmez; ancak Zig’de yaygın generic işleri anlamak için bir başlangıç noktasıdır

Aynı Zig kodunu derleme zamanında çalıştırma

  • Zig, çalışma zamanı, comptime ve derleme sisteminde aynı dili kullanır
  • Fizz Buzz örneği, fizzBuzz(writer) fonksiyonunu önce normal bir çalışma zamanı çıktı fonksiyonu olarak yazar
    • 1den 100e kadar dolaşır
    • 3 ve 5in katları için fizzbuzz, 3ün katları için fizz, 5in katları için buzz, geri kalanlarda sayıyı yazdırır
  • Aynı fizzBuzz fonksiyonu bir comptime bloğu içinde çalıştırıldığında tüm çıktı önceden hesaplanabilir
    • std.io.countingWriter(std.io.null_writer) ile önce gereken bayt sayısı hesaplanır
    • Hesaplanan uzunlukla buffer: [cw.bytes_written]u8 dizisi oluşturulur
    • std.io.fixedBufferStream(&buffer) içine yeniden çıktı yazılarak full_fizzbuzz değeri oluşturulur
  • Yalnızca kritik bölüm ölçüldüğünde, önceden hesaplanmış sürüm yaklaşık 9 kat daha hızlı çalışır
    • Örneğin kendisi küçük olduğundan toplam çalışma süresi başka etkenlerden daha fazla etkilenir
  • comptime ile runtime arasında erişilebilen değerler ve özellikler bakımından farklar vardır
    • comptime_int, comptime_float, type değerlerine yalnızca comptime’da erişilebilir
    • Bazı fonksiyonlar yalnızca comptime argümanları kabul eder ve fiilen comptime’a özel hâle gelir
    • Sistem çağrıları veya bunları kullanan özelliklere yalnızca çalışma zamanında erişilebilir
  • Bu özel özellikleri kullanmayan kod, comptime ve runtime’da aynı şekilde çalışır

comptime’ı kısmi değerlendirme olarak anlamak

  • comptime, derleme sürecinde gerçekleşen kısmi değerlendirme (partial evaluation) olarak görülebilir
  • Kısmi değerlendirme; bir fonksiyona argümanların yalnızca bir kısmı verilmişken, sadece zaten bilinen değerleri kullanan ifadeleri önce ikame edip hesaplayarak, geriye kalan bilinmeyen argümanları alan yeni bir fonksiyon oluşturma yöntemidir
  • Dizi toplama örneği değerlendirme sürecini adım adım gösterir
    • for döngüsü her yinelemenin ayrı ifadelerine ayrıştırılır
    • array[0], array[1], array[2] sırasıyla 1, 2, 3 ile değiştirilir
    • sum 0 → 1 → 3 → 6 şeklinde güncellenir
    • Sonunda std.debug.print(..., .{6}) biçimine kadar sadeleşir
  • Yapı alanlarını toplama örneği de aynı şekilde okunabilir
    • inline for comptime’da çalıştığından "a", "b", "c" alanları için ayrı ifadelere açılır
    • @field(my_struct, "a"), my_struct.a hâline gelir
    • Nihai fonksiyon doğrudan sum += my_struct.a, sum += my_struct.b, sum += my_struct.c içeren bir biçime dönüşür
  • Bu yöntem, niyeti doğrudan kodla ifade ederken alanlar değiştiğinde toplama fonksiyonunu elle güncelleyin diyen yorumlar bırakma ihtiyacını azaltır

Derleme zamanı değerlendirmesi ve çalışma zamanı kodu üretimi

  • Zig comptime, derleme zamanı değerlendirmesi ile çalışma zamanı kodu üretiminin birleşimi olarak da görülebilir
  • Girdi kodu derleyici tarafından çalıştırılır
    • Derleme zamanında bilinebilen ifadeler hemen değerlendirilir
    • Çalışma zamanı değerleri gerektiren ifadeler çıktı koduna eklenir
  • Bu bakış açısı Zig derleyicisinin gerçek işleyiş biçimine en yakın olandır
    • Zig önce söz dizimini ayrıştırır
    • Kodu sanal makine için bytecode’a dönüştürür
    • VM mümkün olan kısımları değerlendirir; çalışma zamanı işlemesi gerektiren kısımlar ise yeni bytecode olarak yayılır
    • Yeni bytecode daha sonra makine koduna dönüştürülür
  • Çalışma zamanı girdisi olan if gibi koşullu ifadelerde iki yol da üretilir
  • Ölü kod semantik analizden geçirilmez
    • Hatalı bir fonksiyon yazılsa bile gerçekten kullanılana kadar derleme hatası oluşmayabilir
    • Bu özellik derlemeyi daha verimli hâle getirir ve #ifdef olmadan doğal koşullu derlemeyi mümkün kılar
  • Zig’de tip adları da comptime’da type değerini değerlendiren ifadelerdir
    • Fonksiyon argümanı tipi gibi basit görünen tip adları bile comptime değerlendirmesinin sonucudur
    • Bu özellik önceki generic örneğini mümkün kılar
    • Gerekirse tip daha karmaşık ifadelerle hesaplanabilir
  • Zig’in statik analizi, diğer birçok statik tipli dile göre daha karmaşıktır
    • Tüm tipleri ortaya çıkarmak için derleyicinin önemli bir bölümünün çalıştırılması gerekir
    • Araçlar yetişene kadar kod tamamlama gibi editör özellikleri her zaman iyi çalışmayabilir

Metinsel kod üretimiyle karşılık ilişkisi

  • Zig comptime biçim olarak metinsel kod üretiminden farklıdır; ancak benzer sorunları çözebilir
  • Kod üretim fonksiyonu writeSumFn, writer.print ile sumFields fonksiyonunun kaynak kodunu yazdırır
    • Üreteçte çalışan kod Zig comptime kısmına karşılık gelir
    • Üretecin ürettiği kod çalışma zamanı koduna karşılık gelir
  • Zig’in comptime sürümü aynı mantığı daha doğrudan ifade eder
    • std.meta.fieldNames(MyStruct) ile alan adları elde edilir
    • inline for ve @field ile alan erişim kodu oluşturulur
  • Tip bilgisini girdi olarak kullanan kod üretimi Zig’de daha basit hâle gelir
    • Metinsel üretim yönteminde tip adı ve alan adı bilgilerinin nereden alınacağı ayrıca çözülmelidir
    • Zig’de tipin kendisi ve alan bilgileri comptime’da doğrudan ele alınabilir
  • Harici belirtim gibi girdiler kullanılıyorsa dosya içeriği @embedFile ile dahil edilip her zamanki gibi ayrıştırılabilir
  • Generic yapı örneğinde comptime, tip adı referanslarını metinsel kod üretiminden daha doğrudan ele alır
    • Metinsel üretimde MyStruct_{s} gibi adları string olarak birleştirip tutarlı şekilde eşleştirmek gerekir
    • comptime’da GenericMyStruct(T) gibi fonksiyon doğrudan kullanılır
  • İstisnalar da vardır
    • Alan adları comptime’da belirlenen bir tip oluşturulabilir
    • Bu durumda alan tanımları listesini içeren bir belirtimle yerleşik fonksiyon çağrılmalıdır
    • Böyle tiplerde metot gibi bildirimler tanımlanamaz
    • Kodun ifade gücünü kendi başına sınırlamaz; ancak başka koda sunulabilecek API biçimini sınırlar
  • C gibi metinsel makrolarla yapılabilen makul işlerin çoğu comptime ile de yapılabilir; ancak kodun görünümü oldukça farklı olabilir
  • Zig, metinsel makrolar gibi anahtar sözcükleri başka adlarla değiştirme özelliği sunmaz

Daha fazla okuma ve standart kütüphane örnekleri

  • Zig’in kendisi yalnızca comptime’a dayanan bir dil değildir; resmi web sitesinden daha fazlası öğrenilebilir
  • Dil referansı comptime’ın somut özelliklerini ele alır
  • Zig standart kütüphanesinde comptime kullanım örnekleri vardır
    • std.debug.printin kullandığı format fonksiyonu güçlü bir generic fonksiyondur
      • Birçok dil format string’ini çalışma zamanında ayrıştırır ve erken hata yakalama için ayrı doğrulayıcılar ekleyebilir
      • Zig, format string’ini comptime’da ayrıştırarak verimli çıktı kodu üretir ve tüm doğrulamaları da derleme zamanında yapar
    • ArrayList görece basit ama tam özellikli bir generic container’dır
    • Zig’in main fonksiyonu birden fazla dönüş tipine sahip olabilir ve bu derleyici sihri değil, normal comptime kodu ile işlenir

1 yorum

 
GN⁺ 2025-01-08
Hacker News yorumları
  • Derleme zamanı programlama konusunda hâlihazırda keşfedilmiş sorunları sorgusuz sualsiz övmektense daha derinlemesine ele alınmasını isterdim
    Aşamalı programlama yeni değil; Lisp ailesinde de onlarca yıldır benzer şeyler yapılıyor, ancak bu süreçte birçok tasarım ödünü ve sorun ortaya çıktı. Örneğin bu tür generics, parametriklik (parametricity) ilkesini bozarak yalnızca bir fonksiyonun tip imzasına bakıp çıkarım yapmayı zorlaştırıyor. Zig’in özyinelemeli generic tipleri nasıl ele aldığı da belirsiz; tip denetimi ile derleme zamanı hesaplamalarının ne zaman ve hangi sırayla etkileştiği de önemli bir tercih. Yazı, derleme zamanı kodunun yalnızca değerler değil kod da üretebildiğini söylüyor ama hijyen (hygiene) konusunu ele almıyor. İlgili tartışma için https://typesanitizer.com/blog/zig-generics.html iyi bir kaynak

    • Zig’i epey seviyorum; birkaç yıldır takip ediyor ve ara sıra kullanıyorum, ama comptime özellikle generics, karmaşık veri yapılarının derleme zamanında ilklendirilmesi ve hedefe özel kod üretimi gibi durumlarda parlıyor
      Yine de başka durumlarda Zig kodunda comptime görünce “ah…” dediğim zamanlar oluyor. Lisp makroları gibi, aslında hiç var olmayacak ya da kod yapısı daha iyi kurulsa ortadan kalkacak sorunlardan kaçmak için kullanılması kolay. Asıl yazıdaki, struct alanlarını dolaşıp değerleri toplama örneği insanların comptimeı pratikte kullanma biçiminin tipik bir örneği; ancak çoğu durumda std.enums.EnumArray gibi gerçekten dolaşılabilir bir veri yapısı kullanmak daha iyi
    • Parametrikliğin bozulması derken, pratikte çalışan bir programcının fonksiyonun davranışını anlama düzeyinden mi, yoksa tip lambda hesabı gibi bir tip teorisi sistemi içinde çıkarım yapma düzeyinden mi söz edildiğini merak ediyorum
      Teorik olarak endişe açık, ama pratik dillerde bunun ne kadar önemli olduğu ayrı bir konu. C++ şablonları da şablon özelleştirmesi yoluyla parametrikliği bozar, fakat pratikte bu büyük bir sorun olmaktan ziyade optimizasyonu mümkün kılar. Örneğin std::vector<bool> gibi her öğeyi gerçekten 1 bit olarak saklayan bir implementasyon, ancak bu tür bir esneklik varsa mümkün olur
    • Yazının yazarı olarak, bu yazı bir buluşmada anlatmaya çalıştığım şeyi iyi ifade edemememin ardından toparlamak için yazıldı; bu yüzden eleştiriden çok açıklamaya odaklandım
      Zig tarzı comptimeı, daha statik biçimde tanımlanmış fonksiyon imzalarına kıyasla çıkarılabilirlik ile ifade gücü arasında doğrudan bir ödünleşim olarak görüyorum. Yalnızca bu tür çıkarımı tipler üzerinden yapan kodu etkiler ve gerektiğinde seçilebilen bir kısımdır. Tip imzasının yeterli olmadığı durumlarda bile birkaç onlarca satır kaynak kodu okuyunca kullanım biçimi genelde netleşti; uzun süre kafamın karıştığı olmadı. Özyinelemeli generic tip örneklerinde, tanımlanmakta olan adı kullanırsanız “dependency loop detected” alınır ama bunu aşmanın yolları var; yazıdaki generic örneği de kendi kendisine referans veriyor. Tip denetimi comptime sırasında gerçekleşir; örneğin ilk @compileLog("Hi") çalışır, ama ardından const a: u32 = "42"; satırında tip hatası olursa ikinci log’a kadar gidilmez. comptime ile çalışma zamanı arasındaki tip denetiminde ince sorunlar çıkabilir, ancak bunlar ancak epey anlaşılması güç kodlarda görülür ve kolayca çözülür; çekirdek ekibin de bundan haberdar olduğu için 1.0’dan önce ele alınmasını bekliyorum. Hijyenin tam olarak ne anlama geldiği konusunda daha fazla açıklama gerekiyor
    • Yalnızca fonksiyon bildirimine bakarak çıkarım yapabilmek, derleme zamanında yürütmeden ayrı bir konu
      Bir fonksiyonun net bir mantıksal amacı varsa, adı ve parametre adları iyi verilmişse yalnızca bildirime bakarak da çıkarım yapılabilir. Parametre etiketleri, tip adları gibi programcının belirleyebildiği kısımlar da adın bir parçası sayılabilir. Bağlantısı verilen yazının başlıktaki sonucuna katılıyorum, ancak anlamlı bir argümandan çok puan toplamaya çalışan münazara takımı tarzı bir yazıya yakın. Daha iyi çerçeve esneklik ile karmaşıklık olurdu. Sabit bir generic sistemi iyi tasarlanırsa programlanabilir olana göre daha basit ama daha az esnektir. Zig’in avantajı, metaprogramlama dilinin normal dille neredeyse aynı olması ve bu normal dilin kendisinin de basit olması sayesinde ek karmaşıklık maliyetini azaltması. Yine de derleme zamanı kodu ile çalışma zamanı kodu iç içe geçiyor ve ipuçları az olduğundan, programcının neyin ne zaman çalıştığını ayırt etmesini zorlaştıran bir karmaşıklık ortaya çıkıyor. Dil sunucusu ya da editör eklentilerinin comptime koduna farklı bir arka plan rengi veren bir “comptime shader” sunması nasıl olurdu diye düşünüyorum
    • Bu konunun 15 dakikalık bir demoya dayanarak tartışılması ve gerçek ödünleşimlere dair anlayışın eksik olması can sıkıcı. Bağlantısı verilen Varun Gandhi yazısı mükemmel
      Rust deneyimime göre insanların const generics ile yapmak istediği birçok şey, comptime benzeri bir özellik olsaydı daha kolay olurdu. Parametrikliği korurken const generics üzerinde aritmetiğe izin vermek implementasyonu zor bir şey; eğer gerçekten istenen “çıktı boyutu N olan bir hash fonksiyonu trait’i” gibi bir şeyse, bu amaç için parametriklikten vazgeçip N’den trait’i daha önceki bir kod üretim aşamasına taşımak kabul edilebilir olabilir. Ama Rust makroları bu şekilde kullanılmak için hem fazla esnek hem de zahmetli. Yine de parametrik polimorfizmi saf bir kod üretim özelliğiyle değiştirdiğiniz anda sıkıntılı yol açılır
  • D’de 17 yıl öncesinden beri vardı. D’nin özellikleri düzenli olarak başka dillere taşındı.
    Zig, derleme sırasında çalıştırılacak blokları comptime anahtar sözcüğüyle işaretler; D’de ise çalıştırmayı belirleyen bir anahtar sözcük değil, ifadenin sabit ifade olup olmadığıdır. Örneğin int s = sum(3, 4); çalışma zamanında çalışır, enum e = sum(3, 4); ise derleme zamanında çalışır. Sabit olmayan global değişkenlerden, giriş/çıkıştan ve malloc() gibi sistem işlevi çağrılarından kaçınılırsa, pek çok işlev değiştirilmeden derleme zamanında çalıştırılabilir. D’nin otomatik bellek yönetimi sayesinde bellek ayırma da mümkündür.

    • Sevdiğim kullanımlardan biri statik tablo üretimi.
      Eskiden statik tablo oluşturmak için ayrı bir program yazılırdı; ama derleme zamanı işlev yürütme sayesinde buna gerek kalmadı. tytab dizisinin başlangıç değerleri, diziyi hesaplayıp döndüren bir lambda’dan geliyor. Tam örnek https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ba... adresinde. CTFE’nin bir başka yaygın kullanımı da DSL oluşturmaktır.
    • D’yi yaptığınız için teşekkür etme fırsatını kaçırmak istemem. Ancak derleme zamanı yürütmenin sınırları merak ediliyor.
      Derleyicinin çalıştığı makine ile programın çalışacağı makine farklıysa D derleyicisi doğruluğu nasıl garanti ediyor? Örneğin int s = sum(100000, 1000000) değerinin tüm x86 makinelerde aynı olduğunu derleyici nasıl biliyor, merak ediliyor. CPU nesilleri arasında ince farklar olabilir; pratikte host üzerinde yapılan bir hesaplamanın hedef makinede de aynı sonucu vereceği nasıl garanti ediliyor, yoksa mimari aynıysa host ile hedefin yeterince benzer olduğu mu varsayılıyor, merak konusu.
    • D’nin ImportC özelliği de C koduyla CTFE yapabiliyor.
      int sum(int a, int b) { return a + b; } için _Static_assert(sum(3, 4) == 7, "look ma, check at compile time!"); gibi kullanılabiliyor. C standardı bunu neden eklemiyor bilmiyorum; gayet iyi çalışıyor.
    • Adil olmak gerekirse Zig de aynı işlevi hem çalışma zamanı bağlamında hem de comptime bağlamında çağırabiliyor.
      square(2) çalışma zamanı çağrısı, comptime square(3) ise derleme zamanı çağrısıdır. comptime çağrısı, bir şey derleme zamanı uyumlu değilse derleme hatası üretir; bunun önemli bir özellik olduğunu düşünüyorum. Çünkü derleme zamanında çalışması beklenen kodun, giriş argümanlarındaki değişim nedeniyle kazara çalışma zamanı değerlendirmesine itilmesi durumunda bir uyarı işareti olur.
  • Zig ilginç görünüyor ama operatör aşırı yükleme olmasını isterdim.
    Operatör aşırı yüklemeye karşı argümanların çoğu pek ikna edici gelmiyor. İçeride gerçekte ne olduğunun bilinmediği iddiası yeterli değil; sonuçta add adlı bir işlev de çarpma yapacak şekilde yazılabilir. C++’ın iostreams veya boost::spirit örnekleri sık sık kötüye kullanım olarak gösteriliyor; ama operatör aşırı yüklemesi olan diğer dillerde bu pek görülmüyor ve C++’a özgü bir sorun gibi duruyor.

    • OCaml tarzı çözüm Zig’in kullanım alanlarına iyi uyacak gibi.
      OCaml’de operatörler yeniden tanımlanabilir, ama yalnızca başka bir modülün bağlamı içinde. Örneğin Vec3 modülünde + yeniden tanımlandıysa Vec3.(a + b + c + d) ya da let open Vec3 in a + b + c + d şeklinde kullanılabilir. Kaynağı okurken “bu + nereden geldi?” sorusu oluşmaz ve a.add(b).add(c).add(d) yazmaktan çok daha iyidir. Ancak Zig artık iyice şekilleniyor gibi; bu tür bir sorunu çözecek büyük bir değişikliğin girmesi zor görünüyor.
    • Python ve PHP’deki __ işlevlerinin arkasında ne kadar sihir döndüğünü bilemeyebilirsiniz.
      Zig’in yaklaşımı ferahlatıcı; kodu takip edebilme yeteneği, birkaç karakter daha yazmanın aldığı birkaç saniyeden daha önemli.
    • Operatör aşırı yüklemeyi sevmeme nedenlerinin önemli bir kısmının beklenmedik çalışma zamanı performansı ile ilgili olduğunu düşünüyorum.
      İdeal çözüm, dilin aşırı yükleme olduğunu açıkça gösteren kullanıcı tanımlı operatörler sunması olurdu. Örneğin let c = a |+| b gibi önek/sonek biçiminde bir yapı olursa, koda bakan kişi |+| işleminin aslında bir işlev çağrısı olduğunu anlayabilir. Yine kötüye kullanılabilir, ama temel endişelerden biri azalır.
    • C++’ta operatör aşırı yüklemeyi yalnızca vektör/matris matematiği için kullandım ve o durumda gerçekten faydalıydı.
      Dil, shading dilleri gibi vektör matematiği sözdizimini doğrudan sağlarsa iyi olabilir. Zig’de en azından Clang’in Vector Extension’ına biraz benzeyen @Vector() tipi var; ama ne yazık ki Extended Vector Extension değil. Bkz. https://ziglang.org/documentation/master/#Vector ve https://clang.llvm.org/docs/LanguageExtensions.html#vectors-....
    • Sayı dizileri için temel lineer cebir operatörleri, aşırı yükleme yerine doğrudan dile yerleşik olmalı belki.
      Böyle bir öneri zaten var mı, emin değilim.
  • fieldNames, Nim’in fieldPairs özelliğine çok benziyor ve son derece kullanışlı bir yapı.
    Verimli serileştirmeyi çok kolaylaştırıyor; yakın zamanda fieldPairs kullanarak bir tip için iş parçacığı güvenliği derleme zamanı denetimini yaklaşık 20 satırda gerçekleştirdim. Bu tür özelliklerin programlama dillerinde standart özellikler olması gerektiğini düşünüyorum. Rust’ta en çok eksikliğini hissettiğim şeylerden biri bu; son denediğimde tipsiz makrolarla sınırlıydı. Çok kısıtlayıcı. Bir crate’teki struct için serde uygulanmış olmasını ummaktan başka çare kalmıyor ve aynı alanlara sahip bir struct’ı programatik olarak doğrudan oluşturmak da mümkün olmuyor.

    • Bir ara derleme zamanı reflection üzerine tartışmalar vardı; muhtemelen bu tür özellikleri de kapsayabilirdi, ama ilgili drama ile birlikte ortadan kaybolmuş gibi.
      Oldukça üzücü. serde gibi şeyleri derleme zamanı reflection olsaydı uygulamak çok daha kolay olurdu.
    • Derleme zamanı reflection olursa ORM veya web framework gibi framework’ler oluşturulabilir.
      Tek ödün, bu tür kütüphaneleri kaynak kod biçiminde dahil etmek zorunda olmaktır.
  • Belli bir olgunluğa ulaşmış bir C ayrıştırıcı kütüphanesi yazdıktan sonra, dilin kendisinde metaprogramlamanın mutlaka gerekli olduğu iddiasından pek emin değilim
    Yapılar, serileştirme, özellikler, ölçümleme vb. üretmek istiyorsanız, kaynak dosyayı işleyip kaynak dosya çıktısı veren sıradan bir C programı yazıp bunu derleme betiğinde önce çalıştırmanız yeterli. Bu meta programların nasıl debug edilip test edildiğini merak ediyorum. Benimki sıradan bir C programı olduğu için diğer kodlarla aynı debugger ve araçları aynen kullanıyor

    • İnsanların yapmak istemediği şey de tam olarak bu
    • C# daha doğrusu Roslyn/dotnet bunu oldukça iyi sunuyor
      Derleyicinin kendisi aynı dilde yazıldığı için AST’ye salt okunur erişip C# kaynağı üreten eklentiler ekleyebiliyorsunuz. Debug için iyi bir test framework’ü oluşturmak adına biraz daha çalışma gerekiyor, ama sonrasında standart birim test framework’ü içinde eklentili derleyiciyi çalıştırıp etkileşimli debugger ile inceleyebiliyorsunuz
    • Ryan Fleury ve başkalarının savunduğu yaklaşımla aynı; yeterince iyi bir yöntem
      “C’de rastgele derleme zamanı yürütme: cl /nologo /Zi metaprogram.c && metaprogram.exe, cl /nologo /Zi program.c. Derleme zamanı kodu native hızda çalışır, debug edilebilir, tamamen prosedüreldir ve keyfidir. Derleyicinin kodu çalıştırmasına gerek yoktur.” https://x.com/ryanjfleury/status/1875824288487571873
    • Zig’i pek bilmiyorum ama Lisp’in gücü S-ifadesinde, başka bir deyişle AST’yi manipüle etmesinde yatıyor
      C’de bunu yapmak için kaynak dosyaları işleyen C programı adına eksiksiz bir C ayrıştırıcısı yazmanız gerekir
    • Eskiden Python’da numba JIT ile benzer bir şey yapmıştım
      Python kodu üreten Python kodu yazıp onu tekrar derletmiştim. Bu kırılgan ve berbat bir karmaşaydı; böyle şeyler yapmak zorunda kalmam Python’dan ayrılmamın büyük nedenlerinden biriydi. Bu, tüm fonksiyon argümanlarını string olarak geçirsen olmaz mı diye sormaya benziyor. String tabanlı kod kullananlar var, ama bu nadir olmalı ve dil bundan kaçınmanın yolunu sunmalı
  • İlginç bir kalıplardan biri, derleme zamanında yapı oluşturabilmek
    PyTorch’ta JSON dosyası oluşturup, Zig’in @embedFile’ı ile okuyup, belirli bir run metoduna sahip bir yapı oluşturarak sinir ağını gerçekleştiren bir deney yapmıştım. Teorik olarak derleyicinin sinir ağını doğrudan optimize edebilmesini sağlıyor. Büyük bir avantajını henüz kanıtlayamadım, ama tüm ağın stack üzerinde olması ve dinamik tahsis olmaması da var. Bunun iyi olup olmadığından emin değilim

    • Bunu comptime yerine Python ile bir kod üreteci yazarak yapmıştım
      comptime Zig’in özellikle hızlı olacağından emin değilim ve yapı oluşturan JSON ayrıştırıcısını her seferinde çalıştırmak da istemiyorum
    • Derleme süresini nasıl etkilediğini merak ediyorum
  • İlginç olsa da, böyle durumlarda “D bunu önce yaptı” tarzı yorumlara katılasım geliyor

    • Doğru, üstelik hijyenik biçimde ele alınıyor ve önişlemci yaklaşımı da değil
  • Zig’in comptime’ı sizi şaşırttıysa, derleme zamanı kod değerlendirmesi ve tam AST makro sistemi olan Nim’e de mutlaka bakmaya değer

    • Nim eğlenceli bir dil ama “ciddi” işler için düşüneceğimi sanmıyorum
      Diğer niş dillerle aynı ekosistem sorunları var; buna bir de tartışmalı bir maintainer, uzun süre kalmıyor gibi görünen çekirdek katkıcılar ve bir kripto para şirketinden gelen ana finansman gibi unsurlar ekleniyor. 10 yıl önce bunlar beni rahatsız etmezdi, ama şimdi durum farklı
    • Zig’in istisna olmaması gibi bir avantajı var
      Nim de istisnalardan uzaklaşmaya çalışıyor gibi görünüyor, ama istisnalar fonksiyonları kirletir ve istisna fırlatan fonksiyonları kullanmasanız bile onları düşünmek zorunda bırakır[1]. Görünmeyen kontrol akışlarıyla uğraşmak için hayat çok kısa. [1]: https://github.com/status-im/nim-stew
  • Zig genel olarak oldukça iyi bir dil ve gereken işi yapıyor
    Amacından sapmaması çok önemli; bu yüzden bazı dillerin sırf kullanılıyor diye her yerde kullanılmasından pek hoşlanmıyorum

  • Zig’in metaprogramlama yetenekleri ile Rust’ın dev ekosistemini, topluluğunu ve güvenliğini birleştiren bir şey olsaydı keşke
    Dil tasarımı açısından Zig’i Rust’tan çok daha fazla seviyorum, ama acemi bir hobi programcısı olarak, en azından şu anda Zig ile gerçekten faydalı ya da güvenilir bir şey yazabileceğime güvenmiyorum

    • Rust’a alışkın biri olarak Zig’i kısa süre denedim ve çabucak vazgeçtim
      Çünkü derleyici bu tür sorunları derleme zamanında bulmamda yardımcı olmuyordu. Zig’in böyle bir vaat sunmadığını biliyorum, ama benim için belirleyici bir eksik olduğu için Zig bana uygun dil değil gibi. Öte yandan comptime kavramını Rust makrolarından daha çok seviyorum
    • Rust topluluğunun Zig’den uzak durmasını isterim. Şaka yapıyorum, ama büyük ölçüde ciddiyim