Clojure 1.12.0 Dirilis
(clojure.org)- Clojure 1.12.0 diumumkan sebagai rilis terakhir berbasis Java 8 sebelum rilis berikutnya memindahkan kompatibilitas Java minimum dan baseline bytecode ke Java LTS yang lebih baru, sambil tetap mempertahankan bytecode Java 8
- Di lingkungan virtual thread JDK 21,
lazy-seqdandelaymenggunakan lock alih-alihsynchronized, sehingga mengurangi situasi ketika blocking I/O membuat thread nyata ter-pin - Di REPL, library dapat ditambahkan dengan
add-lib,add-libs, dansync-depstanpa me-restart JVM, tetapi fitur ini dibatasi untuk penggunaan interaktif saat pengembangan - Interoperabilitas Java diperluas dengan penambahan method values,
:param-tags, sintaks kelas array, konversi functional interface,Supplier, dan fungsi pemrosesan JavaStream - Dari sisi performa dan kompatibilitas, rilis ini mencakup spliterator
PersistentVector, pemrosesandrop/partisi yang efisien, pengetatan kebijakan Var interning, perbaikan CVE-2024-22871, serta perapihan identifier serialisasi Java
Kompatibilitas Java 8, keamanan, dan perapihan serialisasi
- Informasi unduhan dan penggunaan Clojure 1.12.0 dapat dilihat di halaman Downloads
- Baseline Java 8 tetap dipertahankan pada rilis ini
- Clojure 1.12 menghasilkan bytecode Java 8, sama seperti Clojure 1.10 dan 1.11
- Rilis berikutnya direncanakan memindahkan bytecode dan kompatibilitas Java minimum ke rilis Java LTS yang lebih baru
- Masalah pinning virtual thread pada JDK 21 telah dikurangi
- Sebelum 1.12,
lazy-seqdandelaymenjalankan kode pengguna di dalam bloksynchronizeduntuk menjamin perilaku yang hanya dieksekusi sekali - Pada JDK 21,
synchronizedbelum berpartisipasi dalam cooperative blocking, sehingga jika kode tersebut melakukan blocking I/O, thread nyata dapat ter-pin - Saat menggunakan
-Djdk.tracePinnedThreads=full, JDK 21 dapat mengeluarkan peringatan untuk situasi ini - Pada 1.12,
lazy-seqdandelaymenggunakan lock alih-alih bloksynchronized
- Sebelum 1.12,
- Perbaikan keamanan untuk CVE-2024-22871 telah diterapkan, dengan advisory terkait di GHSA-vr64-r9qj-h27f
- serialVersionUID untuk kelas-kelas terkait serialisasi Java ditetapkan secara eksplisit
- Tipe data Clojure telah mengimplementasikan antarmuka serialisasi Java sejak Clojure 1.0
- Serialisasi Java hanya berfungsi saat identifier yang dibuat berdasarkan nama kelas, hierarki tipe, dan field serialisasi cocok pada saat deserialisasi
- Clojure tidak menjamin konsistensi serialisasi antarversi, tetapi perubahan ini diterapkan untuk meningkatkan kontrol ke depan agar kompatibilitas tidak rusak lebih dari yang diperlukan
- Dependensi juga diperbarui
spec.alphadiperbarui ke 0.5.238core.specs.alphadiperbarui ke 0.4.74
Fitur untuk menangani library dan tool di REPL
- Saat pengembangan, ada situasi ketika library perlu ditambahkan tanpa me-restart JVM
- Evaluasi eksperimental
- Menambahkan dependensi yang diketahui ke proyek
- Menambahkan library untuk tugas tertentu
- Clojure 1.12 menyediakan fungsi-fungsi baru untuk menambahkan library tanpa kehilangan state REPL
add-lib: mengunduh lib yang belum ada di classpath dan menambahkannya ke classloader- Tidak memperbarui lib yang sudah ada di classpath
- Jika koordinat tidak ada, fungsi ini menggunakan versi Maven terbaru atau versi/tag git terbaru jika nama repository git dapat disimpulkan
add-libs: menyelesaikan beberapa library baru beserta versinya secara bersamaansync-deps: memanggiladd-libsuntuk lib yang ada dideps.edntetapi belum ada di classpath
- Fungsi-fungsi ini hanya ditujukan untuk penggunaan REPL saat pengembangan
- Cara yang benar untuk membangun dan memelihara kode produksi tetap menggunakan
deps.edn - Ketiga fungsi tersebut memastikan bahwa
*repl*terikat ke true clojure.main/replmengikat flag ini secara otomatis- Di REPL
clojure.main, fungsi-fungsi baru tersebut otomatis di-refer ke namespaceuser - Pada REPL lain,
(require '[clojure.repl.deps :refer :all])mungkin diperlukan
- Cara yang benar untuk membangun dan memelihara kode produksi tetap menggunakan
- Resolusi dan pengunduhan library ditangani oleh tools.deps
- Agar
tools.depsdan dependensinya tidak perlu dimasukkan ke classpath proyek saat pengembangan, API baru juga ditambahkan untuk memanggil fungsi melalui Clojure CLI dalam proses terpisah
- Agar
clojure.tools.deps.interop/invoke-toolmemanggil fungsi tool dalam proses terpisah- Classpath tool didefinisikan di
deps.edn - Dependensi tool tidak perlu ditambahkan ke classpath proyek
- Fitur
add-libdibuat menggunakaninvoke-tool, dan juga dapat digunakan untuk membangun atau memanggil tool pengguna secara interaktif - Protokol eksekusi fungsi dapat dilihat di CLI reference
- Classpath tool didefinisikan di
API eksekusi proses eksternal
- Selain namespace
clojure.java.shellyang sudah ada, kini tersedia jalur yang memanfaatkan API baru Java untuk informasi, kontrol, dan pengalihan I/O proses - Clojure 1.12 menambahkan namespace baru
clojure.java.process- Memanfaatkan API terkait proses baru dari Java
- Dirancang agar lebih mudah digunakan dibandingkan pendekatan lama
- Fungsi utamanya adalah sebagai berikut
Perluasan interoperabilitas Java
- Method values ditambahkan sehingga method Java dapat digunakan lebih langsung dalam higher-order function
- Sebelumnya, untuk meneruskan method Java ke
mapdan sejenisnya, method harus dibungkus sendiri sebagai fungsi - Wrapping manual bersifat verbose, sering membutuhkan hint untuk membedakan overload, atau dapat menimbulkan refleksi dan boxing tambahan
- Kini qualified methods dapat digunakan seperti fungsi biasa pada posisi value, dan compiler otomatis menghasilkan fungsi pembungkus
- Jika qualified method tidak dapat di-resolve karena overload, compiler menghasilkan pemanggilan reflektif
- Developer dapat menentukan satu signature method yang diinginkan melalui metadata
:param-tags
- Sebelumnya, untuk meneruskan method Java ke
- Sintaks qualified method menyebutkan kelas dan method secara eksplisit
Classname/method: nilai fungsi Clojure yang memanggil method statisClassname/.method: nilai fungsi Clojure yang memanggil method instanceClassname/new: nilai fungsi Clojure yang memanggil constructor- Untuk membedakan method statis dan method instance, sintaks
Classname/methoddanClassname/.methodharus digunakan
- Metadata
:param-tagsdigunakan untuk resolve method yang di-overload- Qualified method yang digunakan sebagai value hanya menyediakan kelas dan nama method, sehingga method overload tidak dapat di-resolve
:param-tagsadalah vector berbentuk[tag …], dan setiap tag berkorespondensi dengan parameter pada signature yang diinginkan- Placeholder
_dapat digunakan untuk parameter dengan tipe yang tidak di-overload - Jika
:param-tagsdiberikan, compiler harus dapat me-resolve ke satu method pada waktu kompilasi - Sintaks reader metadata baru
^[tag …]menambahkan metadata:param-tagske symbol member
- Sintaks kelas array ditambahkan
- Clojure telah mendukung symbol nama kelas sebagai nilai objek kelas dan type hint, tetapi tidak menyediakan sintaks kelas array selain string
- Kini kelas array dapat dirujuk dengan symbol berbentuk
ComponentClass/#dimensions - Contoh:
String/1,java.lang.String/1,long/2 - Kelas komponen dapat berupa nama kelas lengkap, kelas yang di-import, atau primitive
- Sintaks kelas array dapat digunakan baik sebagai type hint maupun sebagai value
- Interoperabilitas functional interface Java ditingkatkan
- Functional interface Java diberi
@FunctionalInterfacedan memiliki satu method - Fungsi Clojure dapat diteruskan ke pemanggilan method Java yang menerima functional interface jika arity-nya cocok
- Compiler Clojure membuat lambda adapter untuk secara implisit mengonversi fungsi Clojure ke functional interface yang diperlukan
- Untuk menghindari pembuatan adapter berulang di dalam loop, Anda dapat memaksa secara eksplisit dengan memberi hint pada nama binding
let
- Functional interface Java diberi
- Interoperabilitas
Supplierjuga ditingkatkan- Untuk memanggil method yang menerima
Supplieryang memasok nilai, sebelumnya adaptor harus ditulis denganreify - Implementasi
IDerefClojure sepertidelay,future, danatomkini mengimplementasikan interfaceSuppliersecara langsung
- Untuk memanggil method yang menerima
Pemrosesan Stream dan peningkatan performa collection
- Fungsi-fungsi untuk mengonsumsi
Stream, yang semakin sering dikembalikan oleh Java API, dengan gaya Clojure telah ditambahkan- Bersama dukungan functional interface di Clojure 1.12, tersedia fungsi interoperabilitas Stream
(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- Semua fungsi merupakan operasi stream terminal dan mengonsumsi stream
PersistentVectormenyediakan spliterator langsung yang digunakan dalam implementasi stream Java collection- Spliterator adalah iterator yang dapat dibagi untuk traversal paralel yang lebih cepat
- Spliterator kustom baru milik
PersistentVectormendukung paralelisme dan memberikan peningkatan performa yang besar
- Efisiensi pemrosesan
drop,nthrest,nthnext, dan partisi ditingkatkan- CLJ-2713 menambahkan interface internal
IDropyang menunjukkan bahwa collection dapat melakukan drop lebih efisien daripada traversal sekuensial - Interface ini diimplementasikan pada persistent collection dan collection algoritmik seperti
rangedanrepeat - Fungsi baru
partitionv,partitionv-all, dansplitv-atlebih efisien daripada fungsi padanannya yang sudah ada, serta menghasilkan partisi vector alih-alih partisi realized seq
- CLJ-2713 menambahkan interface internal
Pengetatan kebijakan Var interning
- Meng-intern var dalam namespace, berbeda dari aliasing, adalah membuat referensi stabil agar semua reference mendapatkan objek yang sama
- Sebelumnya ada beberapa kasus ketika interned var dapat diganti, dan pada 1.12.0-alpha1 kebijakan ini diperketat
- Jika situasi ini terjadi, peringatan berbentuk
"REJECTED: attempt to replace interned var #'some-ns/foo with #'other-ns/foo in some-ns, you must ns-unmap first"akan muncul
- Jika situasi ini terjadi, peringatan berbentuk
- Kebijakan ini menangani akar masalah yang terlihat ketika fungsi baru, terutama
abs, ditambahkan keclojure.corepada Clojure 1.11.0
Daftar perubahan lengkap
- Daftar perubahan lengkap Clojure 1.12.0 tersedia di changelog resmi
1 komentar
Komentar Hacker News
Ini benar-benar rilis besar dan punya banyak fitur baru yang keren
Secara pribadi, saya paling suka add-libs. Sekarang kita bisa membuat demo satu file atau contoh minimal untuk mereproduksi isu, sehingga hambatan untuk membagikan potongan kode kecil yang bisa dijalankan jadi jauh lebih rendah
Library Java juga bisa didemokan tanpa boilerplate Java. Setelah mencoba-coba di REPL, tempelkan kodenya di tempat seperti komentar HN, lalu siapa pun bisa mereproduksi dan menjalankan “setup” yang sama persis. Tidak perlu meng-clone repositori
Saya kira rilis ini akan ditunda sampai Clojure/conj 2024. Tidak ada dasar khusus, tetapi Clojure 1.10 keluar sekitar Clojure/conj 2021, dan pengumuman Datomic gratis juga terjadi di awal Clojure/conj 2023
Meski begitu, saya masih menunggu spec2. Saat ini saya mengakali kekakuan spec dengan Malli, tetapi itu bukan warga kelas satu di Clojure. Terutama karena macro tidak bisa diperiksa, dan ini memang bagian yang disengaja dalam desain compiler Clojure. Namun, jika skema Malli dimanipulasi sebagai data, ide schema/select bisa ditiru
Berkat perubahan functional interface, sekarang fungsi bisa langsung diteruskan tanpa perlu mempertahankan macro utilitas seperti
(defmacro ->Consumer [f] ...)Faktanya, Clojure core juga memeriksa pemanggilan macro dengan spec, sehingga ketika pemanggilannya salah, terkadang jejaknya bisa terlihat di stack trace. Saya penasaran apakah yang dimaksud berbeda
Sangat menyenangkan melihat kode lama tetap berjalan apa adanya meski ada banyak fitur baru. Upaya konsisten untuk menghindari breaking compatibility benar-benar terlihat hasilnya
Jika ingin tahu lebih banyak tentang Clojure, ada baiknya melihat konferensi Clojure/conj yang diadakan pada 23–25 Oktober di Alexandria, Virginia: https://2024.clojure-conj.org
Senang melihat add-libs dan sync-deps masuk. Sekarang tampaknya hampir tidak ada, atau bahkan sama sekali tidak ada, alasan untuk menutup sesi
Rilis ini tampak cukup berbeda cakupannya dibanding rilis-rilis sebelumnya, dan menarik karena isinya banyak. Namun, karena lajunya lebih cepat, semoga beberapa rilis ke depan tidak berubah menjadi gumpalan yang kusut
Perubahan functional interface sangat besar. Clojure paling bagus ketika tetap dekat dengan Java lewat interoperabilitas yang hati-hati, dan perubahan ini menutup satu celah besar
Saya penasaran apa kabar spec. Apakah sudah ditinggalkan? Saya ingin tahu apakah ada kabar yang bisa dinantikan
Ini terlihat seperti rilis yang cukup solid, dan saya senang Clojure masih berjalan dengan baik
Bukan bermaksud trolling. Saya ingin memilihnya, dan secara engineering tampak seperti keputusan yang bagus. Tetapi jika popularitas dan kontributornya sedang turun drastis, itu bisa menjadi penghambat dalam waktu dekat
[0] https://www.clara-rules.org/
Mengubah developer yang sudah ada menjadi developer Clojure kini lebih mudah daripada sebelumnya
Masalah besar di awal[0] adalah membaca kode, dan AI seperti ChatGPT atau Claude sangat bagus dalam menjelaskan kode Clojure yang sudah ada. Akibatnya onboarding developer bisa jauh lebih cepat
[0] Setelah beberapa minggu, membaca Clojure terasa alami, dan kita bahkan lupa bahwa dulu pernah tidak bisa membacanya
Banyak peningkatan yang keren. Biasanya ini adalah bahasa keluarga Lisp utama yang saya pilih