3 puan yazan GN⁺ 2024-10-25 | 1 yorum | WhatsApp'ta paylaş
  • Pretty C, C ile uyumlu yeni bir betik dili olup dinamik tipleme, jenerik yineleme ve kaynak takibi gibi kullanışlı özellikleri C programlarına ekler
  • Kullanım şekli, yalnızca pretty.h eklenerek çalışan header-only kütüphane biçimindedir; mevcut C dosyaları ve C kütüphaneleriyle birlikte kullanılabilir
  • Sunulan özellikler arasında string, any, nil gibi takma adlar, var/let tür çıkarımı, print/println jenerik çıktı, equal jenerik karşılaştırma ve okunması kolay üçlü ifade makroları bulunur
  • Yineleme ve bellek işlemlerini azaltmak için foreach, forthese, fortimes, forrange, new, vector, delete, with, lambda, try/catch gibi makro tabanlı sözdizimi sağlar
  • Bazı özellikler GCC, Clang, C23+, C11+ gibi koşullara bağlıdır ve with ile bağlanan değişkenler void * olduğundan kullanım öncesinde tür dönüşümü gerekebilir

Pretty C'nin hedefi ve kullanım şekli

  • Pretty C, C ile uyumlu bir betik dilidir ve C programlarına dinamik tipleme, jenerik yineleme, kaynak takibi ve çeşitli sözdizimi kolaylıkları ekler
  • Mevcut C ve C kütüphaneleriyle geri uyumluluğu korur
  • Lua, Python, JavaScript ve Lisp'ten ilham alır
  • Kurulum için depo klonlanabilir veya yalnızca pretty.h dosyası kopyalanarak kullanılabilir
    • Herhangi bir C dosyasında #include "pretty.h" ile eklenebilir
    • Include yoluna Pretty C dizini verilerek de kullanılabilir

Varsayılan dahil edilen başlıklar ve basit makrolar

  • Pretty C, standart başlıkları dahil ederek sık kullanılan türlerin ve operatör alternatiflerinin doğrudan kullanılmasını sağlar
    • stdbool.h: true, false, bool
    • stdint.h: uint64_t gibi sabit genişlikli tamsayı türleri
    • iso646.h: && yerine and, || yerine or gibi alternatif operatörler
  • Sık tanımlanan basit makrolar da sunar
    • max, min: iki sayının en büyük ve en küçük değeri
    • len: dizi uzunluğu
    • default: fallback değer sağlama
    • limit: değer aralığını sınırlama
    • between: sayının aralık içinde olup olmadığını kontrol etme
    • divisible: başka bir sayıya tam bölünüp bölünmediğini kontrol etme

Türler ve takma adlar

  • Pretty C, C türleri için kısa tür takma adları sağlar
    • string, char* anlamına gelir
    • byte, char anlamına gelir
    • bytes, char* anlamına gelir
    • any, void* anlamına gelir
    • Tamsayı kısaltmaları olarak uchar, ushort, uint, ulong sunulur
  • Lua ve Lisp'ten etkilenmiş sözdizimi takma adları da içerir
    • eq, is: ==
    • bitnot, bitxor: bit işlemi takma adları
    • success, fail, failure: success == 0 kalıbı için takma adlar
    • below, above, upto, downto: karşılaştırma operatörleri
    • even, odd, positive, negative, zero, empty: sayı ve veri predicate'leri
    • nil: NULL
    • until: olumsuz while
    • elif: else if
    • ifnt, elifnt: if(!...) türü ifadeler
    • repeat: Lua tarzı do takma adı
    • done, finish, pass: break, continue takma adları
    • always, forever, loop, indefinitely: sonsuz döngü ifadeleri
    • never, comment: kodu çalıştırmadan derleyicinin analiz edebilmesini sağlayan ifadeler

Tür çıkarımı, çıktı, karşılaştırma, üçlü ifade

  • Tür çıkarımı, GCC, Clang veya C23+ ile kullanılabilir
    • Örnek olarak var t = time(0);, let lt = localtime(&t);, local at = asctime(lt); biçimleri sunulur
  • Jenerik çıktı, C11+ ile kullanılabilir
    • print, verilen değeri yazdırır
    • println, çıktının sonuna satır sonu ekler
  • Jenerik eşitlik karşılaştırması da C11+ özelliği olarak sunulur
    • equal("NA", line) gibi string karşılaştırmaları
    • equal(0.3, 0.2 + 0.1) gibi karşılaştırma örnekleri bulunur
  • Üçlü operatör, metin tabanlı makrolarla daha okunabilir hale getirilebilir
    • when, okunabilirlik için boş string'e genişler
    • unless, not olarak genişler ve whenin olumsuz biçimi gibi çalışır
    • then: ?
    • other ve otherwise: :
    • only, otherwise bölümü gerekmediğinde kullanılır
    • otherwhen, sonraki koşulu zincirlemek için kullanılır

Yineleme makroları

  • Pretty C, sık kullanılan for döngüsü kalıplarını makrolarla soyutlar
  • foreach (var, type, length, ...)
    • Bir dizi veya bellek bölgesi üzerinde gezinir
    • Her yinelemede var, ilgili dizi öğesine işaret eden bir pointer olur
    • Pointer olduğu için gerekirse öğe yerinde değiştirilebilir
  • forthese (var, type, ...)
    • Verilen değişken sayıda argümanı dolaşır ve her değeri type türündeki var değişkenine bağlar
  • fortimes (var, times)
    • 0'dan başlayıp pozitif bir sayıya kadar süren yaygın kalıbı kısaltır
  • forrange (var, init, target)
    • init ile target arasındaki sayısal aralıkta gezinir
    • init ve target, herhangi bir signed veya unsigned tamsayı olabilir
    • init, targettan büyükse yineleme adımı azalır
  • forrangeby (var, type, init, target, by)
    • Türü belirtilmiş var değişkenini initten targeta kadar by aralığıyla dolaştırır

Atama ve blok yardımcıları

  • Atama makroları, C++'tan etkilenmiş bir biçimle yaygın bellek ayırma kalıplarını sadeleştirir
    • new (type, ...): C++ new benzeri biçimde struct vb. oluşturur
    • vector (length, type, ...): belirtilen uzunluk ve türde dizi ayırmayı ve başlangıç içeriği vermeyi kolaylaştırır
    • delete (...): free ile aynıdır, ancak C++ tarzı ad tercih edildiğinde kullanılabilir
  • Blok yardımcıları, yerel bağlama, ertelenmiş çalıştırma ve blok düzeyinde işlemler için makrolar sunar
    • lambda (ret, name, ...): GCC, Clang veya C++ ile iç içe fonksiyon, lambda ve closure benzeri yapıları C'de kullanmayı sağlar
    • with (var, close, ...): kaynak serbest bırakma fonksiyonu closeu önceden vererek dinamik ayrılan nesneler veya dosya tanıtıcıları için kullanışlıdır
      • Dezavantaj olarak bağlanan var, void * olduğundan kullanmadan önce istenen türe dönüştürmek gerekebilir
    • defer: kaldırılmıştır; yerine yeni kullanılabilir deferin kullanılması önerilir
    • try ve catch: C'de hata işlemeyi daha gösterişli bir biçimde yazmayı sağlar
    • NOERR, NOERROR: hata switch-case kolaylığı için sunulur

Katkı yöntemi

1 yorum

 
GN⁺ 2024-10-25
Hacker News yorumları
  • C içinde alana özgü dil oluşturma geleneği epey eskidir
    Stephen Bourne, shell’i ALGOL ile yazmak istiyordu; bu yüzden C önişlemcisini ısrarla zorlayıp sonunda kendi tercih ettiği dile benzer görünmesini sağladı
    https://www.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd/sh...

  • Bunun bir şaka mı olduğunu, yoksa yazarın gerçekten kafasının mı karışık olduğunu açıklayabilecek biri var mı merak ediyorum
    Hiçbir şey mantıklı değil. “Scripting” de değil; “güçlü tip” getirdiğini söylüyor ama tiplere hiçbir şey yapmıyor; Lua ve Lisp’ten esinlendiği söylenen operatör takma adları ise aslında iki dilde de yok. Ama bariz bir parodi gibi de görünmediği için gerçekten kafa karıştırıyor

    • Ciddi gibi görünüyor. “Lua, Python, JavaScript, Ruby ve diğer onlarca dili çöpe atın. Pretty C, ışık hızında ve üstelik güçlü tipli nihai scripting dilidir!!” diyor
    • Yazarın kafasının karışık olduğunu hiç düşünmüyorum. Tabii kafa karışıklığı kendi başına sorun değil
  • Scripting dili olduğunu iddia ediyor ama hâlâ programı derlemek gerekiyor. Yuh yani
    CINT’i (https://root.cern.ch/root/html534/guides/users-guide/CINT.ht...) ekleyince anında çalıştırma da REPL de mümkün oluyor

    • Bu deponun amacı acı çektirmekse, dosyaya bir shebang ekleyip çalıştırılabilir yapmak yeterli olmaz mı diye düşünüyorum [0]
      Eskiden ./foo’nun nasıl çalıştığını ve ELF dosyalarının nasıl yürütüldüğünü ayrıntılı anlatan bir blog yazısı görmüştüm. Aynı yöntemle .c programlarını kaydedip derledikten sonra çalıştırmak da mümkün olabilir
      [0] https://gist.github.com/jdarpinian/1952a58b823222627cc1a8b83...
    • Onun yerine tcc kullanmak daha iyi olur [0]. O canavardan çok daha hafif ve C++, değil C
      [0] https://bellard.org/tcc/tcc-doc.html
    • CERN artık cling kullanıyor (https://github.com/root-project/cling)
    • Scripting dilinin derlenemeyeceğine kim karar vermiş ki? Ayrıca Clang-REPL de bunu REPL dostu hâle getirmenin başka bir yolu
  • “C geliştiricilerine diyabetik kalp krizi geçirtecek kadar sözdizimsel şeker sunar.”
    Bu ifadeye bayıldım

  • CNoEvil[0] ve ogw[1]’ye eklenmesi gereken birkaç şey görüyorum. Bu proje birkaç ayda bir yeniden gündeme geldikçe sanki hep daha fazlası çıkıyor
    [0] https://git.sr.ht/~shakna/cnoevil3/
    [1] https://git.sr.ht/~shakna/ogw

    • “Sayısız kötü fikri alıp iğrenç bir canavara ezip yoğuruyor.”
      İçten içe, bütün kalbimle sevmeye başladığım bir cümle
  • Bu, Python 2 ile aynı hatayı yapıyor. Dizeler ve baytlar aynı tip değildir ve öyle ele alınmamalıdır

    • Shell metni, yani argv içindeki değerler ya da alt süreç çıktısının tipi ne sayılmalı merak ediyorum
      İçinde rastgele çöp değerler bulunabileceği için geçerli UTF-8 dizesi değildir; ama awk ve grep gibi araçlar her yerde kullanılıyor
      Dizeler ve baytlar aynı genel tip olarak görülebilir; ancak geçerli UTF-8 baytlarına içeride ayrı bir tip vermenin faydalı olduğu durumlar var. Rust bu kısmı OsString ve String ile genel olarak iyi ele alıyor
    • Bu projenin pretty.c olduğu ve “C ile tüm kütüphanelerle geriye dönük uyumluluk” amaçladığı söylendiğine göre, C’nin çok baytlı dizelerini korumaktan daha mantıklı bir seçenek var mı emin değilim
      https://en.cppreference.com/w/c/string/multibyte
    • Katılmıyorum. Bu ilke şu varsayımların hepsini içeriyor: dize verisi düzgün kodlanır, yalnızca tek bir dize kodlaması vardır (genellikle UTF-8), dize verisi oluşturulduğu anda doğrulanmalıdır, mantıksal codepoint’lerin kesilmesine asla izin verilmez, “geçersiz” baytlar üzerinde dize işlemleri yapılmamalıdır, doğru kodlama doğrulamanın hem başlangıcı hem de sonudur
      Bunların hiçbiri her zaman doğru değildir. Doğrulanmış bayt dizilerini yalnızca doğrulama yoluyla oluşturulabilen bir tipe sarmak faydalıdır; ama bunu yaptıktan sonra Utf8String ile EmailAddress fiilen aynı sınıfa girer. Tip sisteminde yalnızca kodlamayı özel muameleye tabi tutmak için bir neden yok
    • “Dize”yi nasıl tanımladığınıza bağlı
      “İnsan tarafından okunabilir metin” ise, dizelerin rastgele bayt dizileriyle aynı olmadığına katılıyorum. Ama birçok dil bu tanımı zorunlu kılmaz
  • Eskiden incelemem gereken bir C++ kod tabanını hatırlattı. Tamamı Java ile yazılmış gibiydi; her şeyde camelCase, her sınıf değişkeninde getter/setter, her yerde arayüzler vardı

    • Daha doğru dürüst görmemişsin. Unix Seventh Edition’ın Bourne shell kaynak koduna bakmak yeterli
      https://minnie.tuhs.org/cgi-bin/utree.pl?file=V7/usr/src/cmd...
      ALGOL olmadığına inanmak zor
    • camelCase, getter/setter ve arayüzler çoğu durumda yönergelerden pek farklı değil. Örneğin Windows kodu böyledir; tabii her değişken için değil. Java tasarımının büyük kısmı da C++’tan kopyalanmıştır
    • Java’yı çok uzun süre kullanmış kişilerin yazdığı benzer bir kod tabanı görmüştüm. Hatta sadece std::stringi sarmalayan ama Java tarzı metotlar eklenmiş kendi String sınıfları bile vardı
    • MSVC kullanmadığımız iyi olmuş gibi
      https://learn.microsoft.com/en-us/cpp/cpp/property-cpp?view=...
    • Ben de böyle bir şey yaşadım; üstüne bir de dizgeleri Java’daki gibi f(String *) olarak geçiriyorlardı, C++ kodu f(new String("Hello") şeklindeydi
  • Bu ilginç geldiyse libcello.h da hoşuna gidebilir
    https://www.libcello.org

    • Doğru, esin kaynaklarından biri
  • Tip adları güzel, min gibi yerleşik fonksiyon makrolarının seçimi de kusursuz. Len de hoşuma gitti
    İsimlendirilmiş boolean operatörler biraz fazla gelebilir ama denemeye değer; üçlü operatör zaten baştan okunması zor, dolayısıyla iyileştirilecek çok şey var. Tüm döngü tanımlarına tamamen ikna olmuş değilim ama bazıları mantıklı. Kaynak takibi etkileyici; for... biçimi biraz çirkin, başka bir ad verilebilir gibi duruyor
    Genel olarak epey sağlam bir deneme. Tasarıma 8/10 civarı verirdim. C makrolarıyla eskizlenmiş hâli gerçekten zarif ve fiilen iyi kod gibi görünüyor. Kendim kullanır mıyım bilmiyorum. Sonuçta yeni bir dil ve ben zaten C’yi seviyorum. Yine de uygulanma biçimi çok net; insanların C öğrenmesine ve dil tasarımı üzerine düşünmesine yardımcı olabilir

    • Hepsini kullanmak zorunda değilsin. Benim projelerim genelde yalnızca boolean’ları, len(), max/min ve birkaç operatör makrosunu kullanıyor. Çünkü diğer lezzetli özelliklerin çoğuna henüz ihtiyaç duymadım. O yüzden sadece birkaç operatör makrosunu bile denemeni öneririm
  • if(!...) için ifnt olacaksa, unless ifntten daha okunaklı görünüyor

    • Başka bir isim tartışması olarak, sonsuz for(;;) döngüsüne always denmesi de var
      Başka dillerde loop görmüştüm. Ama Qt buna forever diyor ve bu gerçekten hoş. Ayrıca çok Qt’ye özgü
    • Öte yandan ifnt yüksek sesle söyleyince eğlenceli
    • Doğru. Ama unlessi üçlü koşul için ayırmıştım. Çünkü orada her hâlükârda daha kullanışlı
      Ah, bir dakika, John Tromp’muş. BLC’nin yaratıcısı! Hayranıyım