Clojure 1.12.0 yayımlandı
(clojure.org)- Clojure 1.12.0, Java 8 bytecode’unu korurken, sonraki sürümlerde minimum Java uyumluluğu ve bytecode tabanını daha yeni bir Java LTS sürümüne taşımadan önceki son Java 8 tabanlı sürüm olarak duyuruldu
- JDK 21’in sanal thread ortamında
lazy-seqvedelay,synchronizedyerine lock kullanarak, blocking I/O’nun gerçek thread’leri pinlediği durumları azaltıyor - REPL’de JVM’i yeniden başlatmadan
add-lib,add-libs,sync-depsile kütüphane eklenebiliyor; ancak bu özellik yalnızca geliştirme sırasında etkileşimli kullanım için tasarlandı - Java birlikte çalışabilirliği genişletilerek method values,
:param-tags, dizi sınıfı sözdizimi, fonksiyonel arayüz dönüşümü,Supplier, JavaStreamişleme fonksiyonları eklendi - Performans ve uyumluluk tarafında
PersistentVectorspliterator, daha verimlidrop/partition işleme, daha sıkı Var interning politikası, CVE-2024-22871 düzeltmesi ve Java serileştirme tanımlayıcılarının düzenlenmesi yer alıyor
Java 8 uyumluluğu, güvenlik ve serileştirme düzenlemeleri
- Clojure 1.12.0 indirme ve kullanım bilgileri Downloads sayfasında bulunabilir
- Java 8 tabanı bu sürümde de korunuyor
- Clojure 1.12, Clojure 1.10 ve 1.11 gibi Java 8 bytecode’u üretiyor
- Sonraki sürümler, bytecode ve minimum Java uyumluluğunu daha yeni bir Java LTS sürümüne taşımayı planlıyor
- JDK 21’deki sanal thread pinning sorunu hafifletildi
- 1.12’den önce
lazy-seqvedelay, yalnızca bir kez çalıştırılma davranışını garanti etmek için kullanıcı kodunusynchronizedblok içinde yürütüyordu - JDK 21 itibarıyla
synchronizedhâlâ cooperative blocking’e katılmadığından, ilgili kod blocking I/O yaparsa gerçek thread’i pinleyebiliyor -Djdk.tracePinnedThreads=fullkullanıldığında JDK 21 bu durum için uyarı verebiliyor- 1.12’de
lazy-seqvedelay,synchronizedblok yerine lock kullanıyor
- 1.12’den önce
- Güvenlik düzeltmesi olarak CVE-2024-22871 eklendi; ilgili uyarı GHSA-vr64-r9qj-h27f adresinde yer alıyor
- Java serileştirmeyle ilgili sınıfların serialVersionUID değeri açıkça ayarlandı
- Clojure veri tipleri, Clojure 1.0’dan beri Java serileştirme arayüzünü uyguluyor
- Java serileştirme, sınıf adı, tip hiyerarşisi ve serileştirme alanlarından üretilen tanımlayıcının deserialization sırasında eşleşmesini gerektiriyor
- Clojure sürümler arası serileştirme tutarlılığı garantisi vermese de, gelecekte gereksiz uyumluluk kırılmalarını önlemek için daha fazla kontrol sağlayan bir değişiklik yaptı
- Bağımlılıklar da güncellendi
spec.alpha0.5.238’e güncellendicore.specs.alpha0.4.74’e güncellendi
REPL’de kütüphane ve araç kullanma özellikleri
- Geliştirme sırasında JVM’i yeniden başlatmadan kütüphane eklemeyi gerektiren durumlar olabiliyor
- Deneysel değerlendirme
- Projeye bilinen bağımlılıkların eklenmesi
- Belirli bir iş için kütüphane eklenmesi
- Clojure 1.12, REPL durumunu kaybetmeden kütüphane eklemek için yeni fonksiyonlar sunuyor
add-lib: classpath’te olmayan bir lib’i indirip classloader’a ekler- Zaten classpath’te olan lib’leri güncellemez
- Koordinatlar yoksa, en son Maven sürümünü ya da git depo adından çıkarılabiliyorsa en son git sürümünü veya tag’i kullanabilir
add-libs: birden fazla yeni kütüphane ve sürümü birlikte çözümlersync-deps:deps.edniçinde olup henüz classpath’te olmayan lib’ler içinadd-libsçağırır
- Bu fonksiyonlar yalnızca geliştirme sırasında REPL kullanımı için tasarlandı
- Production kodu derlemek ve sürdürmek için doğru yol hâlâ
deps.ednkullanmak - Üç fonksiyon da
*repl*değişkeninin true olarak bağlanıp bağlanmadığını kontrol ediyor clojure.main/replbu bayrağı otomatik olarak bağlıyorclojure.mainREPL’inde yeni fonksiyonlar otomatik olarakusernamespace’ine refer ediliyor- Diğer REPL’lerde
(require '[clojure.repl.deps :refer :all])gerekebilir
- Production kodu derlemek ve sürdürmek için doğru yol hâlâ
- Kütüphane çözümleme ve indirme işlemleri tools.deps tarafından yapılıyor
- Geliştirme sırasında proje classpath’ine
tools.depsve bağımlılıklarını eklememek için, Clojure CLI üzerinden fonksiyonları ayrı bir süreçte çağıran yeni bir API de eklendi
- Geliştirme sırasında proje classpath’ine
clojure.tools.deps.interop/invoke-tool, araç fonksiyonlarını ayrı bir süreçte çağırıyor- Aracın classpath’i
deps.edniçinde tanımlanıyor - Araç bağımlılıklarını proje classpath’ine eklemeye gerek yok
add-libözelliğiinvoke-toolkullanılarak oluşturuldu; bu yapı kullanıcı araçlarını etkileşimli olarak derlemek veya çağırmak için de kullanılabiliyor- Fonksiyon yürütme protokolü CLI reference sayfasında yer alıyor
- Aracın classpath’i
Harici süreç çalıştırma API’si
- Mevcut
clojure.java.shellnamespace’ine ek olarak, Java’nın yeni süreç bilgisi, kontrol ve I/O yönlendirme API’sini kullanan bir yol eklendi - Clojure 1.12, yeni namespace
clojure.java.process’i ekliyor- Java’nın yeni süreç API’lerinden yararlanıyor
- Mevcut yaklaşıma göre daha kolay kullanılacak şekilde tasarlandı
- Temel fonksiyonlar şunlar
Java birlikte çalışabilirliğinin genişletilmesi
- Method values eklendi; böylece Java metotları higher-order function’larda daha doğrudan kullanılabiliyor
- Daha önce Java metotlarını
mapgibi yerlere vermek için bunları elle fonksiyona sarmak gerekiyordu - Manuel sarmalama ayrıntılıydı; overload ayrımı için hint gerekebiliyor, ayrıca ek reflection veya boxing oluşabiliyordu
- Artık qualified methods, değer konumunda normal fonksiyon gibi kullanılabiliyor ve derleyici wrapper function’ı otomatik oluşturuyor
- Qualified method overload nedeniyle çözülemezse derleyici reflection çağrısı üretiyor
- Geliştiriciler
:param-tagsmetadata’sıyla istenen tek method signature’ını belirtebiliyor
- Daha önce Java metotlarını
- Qualified method sözdizimi sınıfı ve metodu açıkça belirtir
Classname/method: statik metodu çağıran Clojure fonksiyon değeriClassname/.method: instance metodu çağıran Clojure fonksiyon değeriClassname/new: constructor çağıran Clojure fonksiyon değeri- Statik ve instance metotları ayırt etmek için
Classname/methodveClassname/.methodsözdizimi kullanılmalı
:param-tagsmetadata’sı overload edilmiş metotların çözümünde kullanılıyor- Değer olarak kullanılan qualified method yalnızca sınıf ve metot adını verdiğinden overload edilmiş metot çözülemiyor
:param-tags,[tag …]biçiminde bir vektördür ve her tag istenen signature’daki bir parametreye karşılık gelir- Overload edilmemiş tiplerin parametreleri için
_placeholder’ı kullanılabilir :param-tagsverildiğinde derleyicinin bunu derleme zamanında tek bir metoda çözümleyebilmesi gerekir- Yeni metadata reader sözdizimi
^[tag …], üye sembolüne:param-tagsmetadata’sı ekler
- Dizi sınıfı sözdizimi eklendi
- Clojure, sınıf adı sembollerini sınıf nesnesi değeri ve type hint olarak destekliyordu; ancak string dışında dizi sınıfı sözdizimi sunmuyordu
- Artık
ComponentClass/#dimensionsbiçimindeki sembollerle dizi sınıflarına başvurulabiliyor - Örnek:
String/1,java.lang.String/1,long/2 - Bileşen sınıfı tam sınıf adı, import edilmiş sınıf veya primitive olabilir
- Dizi sınıfı sözdizimi hem type hint hem değer olarak kullanılabilir
- Java fonksiyonel arayüz birlikte çalışabilirliği geliştirildi
- Java fonksiyonel arayüzleri
@FunctionalInterfaceile işaretlenir ve tek bir metoda sahiptir - Clojure fonksiyonları, arity uyuyorsa fonksiyonel arayüz alan Java metot çağrılarına geçirilebilir
- Clojure derleyicisi, Clojure fonksiyonunu gerekli fonksiyonel arayüze örtük olarak dönüştüren bir lambda adapter oluşturur
- Döngülerde tekrarlanan adapter üretimini önlemek için
letbağlama adına hint eklenerek bu dönüşüm açıkça zorlanabilir
- Java fonksiyonel arayüzleri
Supplierbirlikte çalışabilirliği de iyileştirildi- Değer sağlayan
Supplieralan metotları çağırmak için daha öncereifyile adapter yazmak gerekiyordu - Clojure’un
IDerefuygulamaları olandelay,future,atomvb. artıkSupplierarayüzünü doğrudan uyguluyor
- Değer sağlayan
Stream işleme ve koleksiyon performansı iyileştirmeleri
- Java API’lerinin giderek daha sık döndürdüğü
Stream’leri Clojure tarzında tüketmek için yeni fonksiyonlar eklendi- Clojure 1.12’nin fonksiyonel arayüz desteğiyle birlikte Stream birlikte çalışabilirlik fonksiyonları sunuluyor
(stream-seq! stream) ⇒ seq(stream-reduce! f [init-val] stream) ⇒ val(stream-transduce! xf f [init-val] stream) ⇒ val(stream-into! to-coll [xf] stream) ⇒ to-coll- Tüm fonksiyonlar terminal stream işlemleridir ve stream’i tüketir
PersistentVector, Java koleksiyonlarının stream uygulamalarında kullanılan spliterator’ı doğrudan sağlıyor- Spliterator, daha hızlı paralel dolaşım için bölünebilen bir iterator’dur
PersistentVectoriçin yeni özel spliterator paralelliği destekliyor ve performansı belirgin biçimde artırıyor
drop,nthrest,nthnextve partition işleme verimliliği artırıldı- CLJ-2713, koleksiyonların sıralı dolaşımdan daha verimli biçimde drop yapabildiğini gösteren iç arayüz
IDrop’u ekliyor - Bu arayüz persistent collection’larda ve
range,repeatgibi algoritmik koleksiyonlarda uygulanıyor - Yeni
partitionv,partitionv-all,splitv-atfonksiyonları mevcut karşılıklarından daha verimli ve realized seq partition’ları yerine vektör partition’ları üretiyor
- CLJ-2713, koleksiyonların sıralı dolaşımdan daha verimli biçimde drop yapabildiğini gösteren iç arayüz
Var interning politikasının sıkılaştırılması
- Bir namespace içinde var interning yapmak, aliasing’den farklı olarak, tüm başvuruların aynı nesneyi almasını sağlayan kararlı bir referans oluşturmaktır
- Daha önce interned var’ın değiştirilebildiği bazı durumlar vardı; 1.12.0-alpha1 ile politika sıkılaştırıldı
- Böyle bir durumda
"REJECTED: attempt to replace interned var #'some-ns/foo with #'other-ns/foo in some-ns, you must ns-unmap first"biçiminde bir uyarı görünür
- Böyle bir durumda
- Bu politika, Clojure 1.11.0’da
clojure.core’a yeni fonksiyonlar, özellikleabs, eklenince görünür hâle gelen sorunun kök nedenini ele alıyor
Tüm değişiklik listesi
- Clojure 1.12.0’daki tüm değişiklikler resmî changelog içinde yer alıyor
1 yorum
Hacker News yorumları
Gerçekten büyük bir sürüm ve pek çok harika yeni özellik var
Kişisel olarak en çok add-libs hoşuma gitti. Artık bir sorunu yeniden üretmek için tek dosyalık demolar veya minimal örnekler oluşturulabiliyor; bu da çalıştırılabilir küçük kod parçaları paylaşmanın önündeki engeli ciddi ölçüde azaltıyor
Java boilerplate’i olmadan Java kütüphaneleri de demo edilebiliyor. REPL’de biraz kurcaladıktan sonra kodu HN yorumu gibi bir yere yapıştırırsanız, herkes aynı “kurulumu” birebir yeniden oluşturup çalıştırabilir. Bir depoyu klonlamaya bile gerek yok
Bu sürümü Clojure/conj 2024’e kadar erteleyeceklerini sanmıştım. Buna dair özel bir dayanağım yoktu ama Clojure 1.10, Clojure/conj 2021 civarında çıkmıştı ve Datomic’in ücretsiz hale gelme duyurusu da Clojure/conj 2023’ün başlarında yapılmıştı
Yine de hâlâ spec2’yi bekliyorum. Şimdilik spec’in katılığını Malli ile aşıyorum, ama Clojure’da birinci sınıf vatandaş değil. Bunun başlıca nedeni makroları denetleyememesi; bu da Clojure derleyicisinin tasarımında bilinçli bir tercih. Yine de Malli şemalarını veri olarak manipüle ederseniz schema/select fikrini taklit etmek mümkün
Fonksiyonel arayüz değişikliği sayesinde artık
(defmacro ->Consumer [f] ...)gibi yardımcı makroları tutmaya gerek kalmadan fonksiyonu doğrudan geçirmek mümkünAslında Clojure core da makro çağrılarını spec ile denetliyor; yanlış çağrıldığında bazen yığın izinde bunun izlerini görebiliyorsunuz. Başka bir anlamda mı söylendiğini merak ediyorum
Bir sürü yeni özellik gelmesine rağmen mevcut kodun aynen çalışmaya devam etmesi gerçekten güzel. Uyumluluğu bozan değişikliklerden kaçınmaya yönelik istikrarlı çaba kendini gösteriyor
Clojure hakkında daha fazla bilgi edinmek isterseniz 23-25 Ekim’de Virginia, Alexandria’da düzenlenecek Clojure/conj konferansına bakabilirsiniz: https://2024.clojure-conj.org
add-libs ve sync-deps’in gelmesine sevindim. Artık bir oturumu kapatmak için neredeyse hiç neden yok gibi, hatta hiç yok gibi görünüyor
Bu sürüm, önceki sürümlere kıyasla kapsam olarak epey farklı görünüyor ve içine girenlerin çokluğu onu ilginç kılıyor. Yine de hızlandığı için birkaç sürüm sonra iç içe geçmiş karmaşık bir yumağa dönüşmemesini umuyorum
Fonksiyonel arayüz değişikliği çok büyük. Clojure, özenli birlikte çalışabilirlik sayesinde Java’ya yakın durduğunda en iyi halinde oluyor ve bu değişiklik büyük bir boşluğu kapatıyor
spec’e ne olduğunu merak ediyorum. Terk mi edildi? Beklemeye değer bir haber var mı merak ediyorum
Oldukça sağlam bir sürüm gibi görünüyor ve Clojure’un hâlâ iyi durumda olmasına sevindim
Trollemek istemiyorum. Seçmek istiyorum ve mühendislik açısından iyi bir karar gibi görünüyor. Ama popülerliği ve katkıda bulunanları hızla düşüyorsa yakın gelecekte sorun çıkarabilir
[0] https://www.clara-rules.org/
Mevcut geliştiricileri Clojure geliştiricisine dönüştürmek hiç olmadığı kadar kolaylaştı
Başta yaşanan büyük sorun[0] kodu okumak; ChatGPT veya Claude gibi yapay zeka araçları mevcut Clojure kodunu açıklamakta çok başarılı. Bunun sonucunda geliştirici onboarding’i çok daha hızlı olabilir
[0] Birkaç hafta sonra Clojure okumak doğal hale geliyor ve eskiden okuyamadığınızı bile unutuyorsunuz
Pek çok güzel iyileştirme var. Genelde elimin gittiği başlıca Lisp ailesi dili