2 पॉइंट द्वारा GN⁺ 2024-09-06 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Clojure 1.12.0 Java 8 bytecode को बनाए रखता है, और इसे बाद की releases में न्यूनतम Java compatibility और bytecode baseline को नए Java LTS पर ले जाने से पहले Java 8 baseline वाली आखिरी release के रूप में संकेतित किया गया है
  • JDK 21 के virtual threads environment में lazy-seq और delay, synchronized की जगह lock का उपयोग करते हैं, जिससे blocking I/O के real thread को pin करने की स्थितियां कम होती हैं
  • REPL में JVM restart किए बिना add-lib, add-libs, sync-deps से libraries जोड़ी जा सकती हैं, लेकिन यह सुविधा सिर्फ development के दौरान interactive उपयोग तक सीमित है
  • Java interoperability बढ़ी है: method values, :param-tags, array class syntax, functional interface conversion, Supplier, और Java Stream processing functions जोड़े गए हैं
  • performance और compatibility के लिहाज से PersistentVector spliterator, efficient drop/partition processing, Var interning policy को सख्त करना, CVE-2024-22871 fix, और Java serialization identifiers की सफाई शामिल है

Java 8 compatibility, security, serialization cleanup

  • Clojure 1.12.0 download और उपयोग की जानकारी Downloads page पर मिल सकती है
  • Java 8 baseline इस release में भी कायम है
    • Clojure 1.12, Clojure 1.10 और 1.11 की तरह Java 8 bytecode generate करता है
    • बाद की releases bytecode और minimum Java compatibility को ज्यादा नए Java LTS release पर ले जाएंगी
  • JDK 21 की virtual thread pinning समस्या कम की गई है
    • 1.12 से पहले, lazy-seq और delay एक बार ही execute होने वाले behavior की guarantee देने के लिए user code को synchronized block के अंदर चलाते थे
    • JDK 21 के मानक के अनुसार synchronized अभी cooperative blocking में हिस्सा नहीं लेता, इसलिए अगर वह code blocking I/O करता है तो real thread को pin कर सकता है
    • -Djdk.tracePinnedThreads=full इस्तेमाल करने पर JDK 21 इस स्थिति के बारे में warning दे सकता है
    • 1.12 में lazy-seq और delay, synchronized block की जगह lock का उपयोग करते हैं
  • security fix के रूप में CVE-2024-22871 शामिल किया गया है, और संबंधित advisory GHSA-vr64-r9qj-h27f पर है
  • Java serialization से जुड़ी classes का serialVersionUID explicit रूप से set किया गया है
    • Clojure data types ने Clojure 1.0 से Java serialization interface implement किया है
    • Java serialization तभी काम करता है जब class name, type hierarchy और serialization fields के आधार पर बनने वाला identifier deserialization के समय match करे
    • Clojure versions के बीच serialization consistency की guarantee नहीं देता, लेकिन जरूरत से ज्यादा compatibility न टूटे, इसके लिए आगे control बढ़ाने वाला बदलाव लागू किया गया है
  • dependencies भी साथ में update की गई हैं
    • spec.alpha को 0.5.238 पर update किया गया है
    • core.specs.alpha को 0.4.74 पर update किया गया है

REPL में libraries और tools संभालने की सुविधाएं

  • development के दौरान कभी-कभी JVM restart किए बिना libraries जोड़ने की जरूरत होती है
    • experimental evaluation
    • project में known dependency जोड़ना
    • किसी खास task के लिए library जोड़ना
  • Clojure 1.12 REPL state खोए बिना libraries जोड़ने के लिए नए functions देता है
    • add-lib: classpath में न मौजूद lib को download कर classloader में जोड़ता है
      • जो lib पहले से classpath में है उसे update नहीं करता
      • coordinates न हों तो latest Maven version, या git repository name infer किया जा सके तो latest git version या tag का उपयोग करता है
    • add-libs: कई नई libraries और versions को साथ में resolve करता है
    • sync-deps: deps.edn में मौजूद लेकिन अभी classpath में न होने वाले libs के लिए add-libs call करता है
  • ये functions सिर्फ development के दौरान REPL उपयोग के लिए intended हैं
    • production code को build और maintain करने का सही तरीका अब भी deps.edn का उपयोग है
    • तीनों functions check करते हैं कि *repl* true से bound है या नहीं
    • clojure.main/repl इस flag को automatic रूप से bind करता है
    • clojure.main REPL में नए functions user namespace में automatically refer हो जाते हैं
    • दूसरे REPLs में (require '[clojure.repl.deps :refer :all]) की जरूरत पड़ सकती है
  • library resolution और download tools.deps संभालता है
    • development के दौरान project classpath में tools.deps और उसकी dependencies डालने से बचाने के लिए, Clojure CLI के जरिए functions को अलग process में call करने वाला नया API भी जोड़ा गया है
  • clojure.tools.deps.interop/invoke-tool tool function को अलग process में call करता है
    • tool का classpath deps.edn में define होता है
    • tool dependencies को project classpath में जोड़ने की जरूरत नहीं होती
    • add-lib feature invoke-tool का उपयोग करके बनाया गया है, और इसे user tools को interactively build या call करने में भी इस्तेमाल किया जा सकता है
    • function execution protocol CLI reference में देखा जा सकता है

External process execution API

  • मौजूदा clojure.java.shell namespace के अलावा, Java के नए process information, control और I/O redirection APIs का उपयोग करने वाला रास्ता बना है
  • Clojure 1.12 नया namespace clojure.java.process जोड़ता है
    • Java के नए process-related APIs का उपयोग करता है
    • मौजूदा तरीके की तुलना में इसे इस्तेमाल में आसान बनाने के लिए design किया गया है
  • मुख्य functions ये हैं
    • start: streams पर पूरा control देता है, और advanced उपयोग के लिए underlying Java objects तक access देता है
    • exec: external process चलाने और complete होने पर stdout लौटाने वाले common case को handle करता है

Java interoperability expansion

  • method values जोड़ी गई हैं, जिससे Java methods को higher-order functions में ज्यादा सीधे इस्तेमाल किया जा सकता है
    • पहले Java methods को map आदि में pass करने के लिए manually function में wrap करना पड़ता था
    • manual wrapping verbose था, overload अलग करने के लिए hints की जरूरत पड़ सकती थी, या extra reflection/boxing हो सकती थी
    • अब qualified methods को value position में normal functions की तरह इस्तेमाल किया जा सकता है, और compiler wrapping function automatically generate करता है
    • अगर qualified method overload की वजह से resolve नहीं होता, तो compiler reflection call generate करता है
    • developers :param-tags metadata से desired single method signature specify कर सकते हैं
  • Qualified method syntax class और method को explicit करता है
    • Classname/method: static method call करने वाली Clojure function value
    • Classname/.method: instance method call करने वाली Clojure function value
    • Classname/new: constructor call करने वाली Clojure function value
    • static method और instance method में फर्क करने के लिए Classname/method और Classname/.method syntax का उपयोग करना होगा
  • :param-tags metadata overloaded methods resolve करने में इस्तेमाल होता है
    • value के रूप में इस्तेमाल होने वाला qualified method सिर्फ class और method name देता है, इसलिए overloaded method resolve नहीं कर सकता
    • :param-tags [tag …] form का vector है, और हर tag desired signature के parameter से correspond करता है
    • non-overloaded type के parameters के लिए _ placeholder इस्तेमाल किया जा सकता है
    • :param-tags देने पर compiler को compile time पर single method में resolve कर पाना चाहिए
    • नया metadata reader syntax ^[tag …] member symbol पर :param-tags metadata जोड़ता है
  • Array class syntax जोड़ा गया है
    • Clojure class name symbols को class object values और type hints के रूप में support करता था, लेकिन strings के अलावा array class syntax नहीं देता था
    • अब ComponentClass/#dimensions form के symbol से array class refer की जा सकती है
    • उदाहरण: String/1, java.lang.String/1, long/2
    • component class fully qualified class name, imported class, या primitive हो सकती है
    • array class syntax type hint और value, दोनों रूपों में इस्तेमाल किया जा सकता है
  • Java functional interface interoperability बेहतर हुई है
    • Java functional interface पर @FunctionalInterface लगा होता है और उसमें single method होता है
    • Clojure function, arity match होने पर functional interface लेने वाले Java method call में pass किया जा सकता है
    • Clojure compiler lambda adapter बनाकर Clojure function को required functional interface में implicitly convert करता है
    • loop में बार-बार adapter creation से बचने के लिए let binding name पर hint लगाकर explicitly force किया जा सकता है
  • Supplier interoperability भी बेहतर हुई है
    • value supply करने वाला Supplier लेने वाले methods को call करने के लिए पहले reify से adapter लिखना पड़ता था
    • Clojure के IDeref implementers जैसे delay, future, atom आदि अब सीधे Supplier interface implement करते हैं

Stream processing और collections performance सुधार

  • Java APIs अब लगातार ज्यादा Stream return करते हैं; उन्हें Clojure तरीके से consume करने के लिए functions जोड़े गए हैं
    • Clojure 1.12 के functional interface support के साथ Stream interoperability functions दिए गए हैं
    • (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
    • सभी functions terminal stream operations हैं और stream को consume करते हैं
  • PersistentVector Java collections के stream implementation में इस्तेमाल होने वाला spliterator खुद provide करता है
    • spliterator ऐसा iterator है जिसे तेज parallel traversal के लिए split किया जा सकता है
    • PersistentVector का नया custom spliterator parallelism support करता है और performance में बड़ा सुधार करता है
  • drop, nthrest, nthnext और partition processing की efficiency बेहतर हुई है
    • CLJ-2713 ने internal interface IDrop जोड़ा है, जो बताता है कि collection sequential traversal की तुलना में ज्यादा efficiently drop कर सकती है
    • यह interface persistent collections और range, repeat जैसी algorithmic collections में implement किया गया है
    • नए functions partitionv, partitionv-all, splitv-at मौजूदा counterparts से ज्यादा efficient हैं, और realized seq partitions की जगह vector partitions बनाते हैं

Var interning policy सख्त

  • namespace में var को intern करना aliasing से अलग है; इसका मतलब stable reference बनाना है ताकि सभी references को same object मिले
  • पहले कुछ cases में interned var replace हो सकता था, और 1.12.0-alpha1 में policy ज्यादा strict हुई
    • ऐसी स्थिति होने पर "REJECTED: attempt to replace interned var #'some-ns/foo with #'other-ns/foo in some-ns, you must ns-unmap first" जैसी warning दिखती है
  • यह policy Clojure 1.11.0 में clojure.core में नए functions, खासकर abs, जुड़ने से सामने आई problem के root cause को address करती है
    • अगर पुराने Clojure version में compiled code में clojure.core में नए जोड़े गए function name जैसा var name हो, तो 1.11.0 runtime में load होने पर वह unbound हो सकता था
    • CLJ-2711 के अलावा, इस area की पिछली fix CLJ-1604 भी rollback की गई

पूरा बदलावों की सूची

  • Clojure 1.12.0 की पूरी बदलावों की सूची official changelog में है

1 टिप्पणियां

 
GN⁺ 2024-09-06
Hacker News की राय
  • यह सचमुच एक बड़ा रिलीज़ है और इसमें बहुत-सी शानदार नई features हैं
    व्यक्तिगत रूप से मुझे add-libs सबसे ज़्यादा पसंद है। अब single-file demo या issue reproduce करने के लिए minimal example बनाया जा सकता है, इसलिए चलने योग्य छोटे code snippets साझा करने की बाधा काफी कम हो जाती है
    Java boilerplate के बिना Java libraries का demo भी किया जा सकता है। REPL में थोड़ा प्रयोग करने के बाद अगर कोड को HN comment जैसी किसी जगह paste कर दें, तो कोई भी उसी “setup” को वैसा का वैसा reproduce करके चला सकता है। Repository clone करने की भी ज़रूरत नहीं है

    • पता नहीं किसी को Groovy याद है या नहीं। Groovy में @Grab annotation है, जो ऊपर बताए गए add-libs जैसा लगभग वही काम करता है, और scripting के लिए बहुत सुविधाजनक है
    • Java में अब REPL और scripting support तो है, लेकिन add-libs जैसी सुविधा अभी उपलब्ध meta commands में नहीं है
  • मुझे लगा था कि इस रिलीज़ को Clojure/conj 2024 तक टाल दिया जाएगा। कोई खास आधार नहीं था, लेकिन Clojure 1.10 लगभग Clojure/conj 2021 के समय आया था और Datomic को free करने की घोषणा भी Clojure/conj 2023 की शुरुआत में हुई थी
    फिर भी मैं अभी spec2 का इंतज़ार कर रहा हूँ। अभी spec की rigidness को Malli से bypass कर लेते हैं, लेकिन वह Clojure में first-class citizen नहीं है। मुख्य वजह यह है कि macros को inspect नहीं किया जा सकता, और यह Clojure compiler design का एक जानबूझकर रखा गया हिस्सा है। हाँ, Malli schema को data की तरह manipulate करके schema/select के विचार की नकल की जा सकती है
    functional interface बदलाव की वजह से अब (defmacro ->Consumer [f] ...) जैसे utility macro को बनाए रखने की ज़रूरत नहीं रही; अब function को सीधे pass किया जा सकता है

    • “maybe not” देखकर मुझे schema/select की सच में ज़रूरत महसूस हुई, इसलिए मैंने Malli के लिए एक library बनाई: https://github.com/eval/malli-select
    • “macros को inspect नहीं किया जा सकता” से आपका क्या मतलब है, यह जानने की जिज्ञासा है। spec के साथ macro पर s/fdef लगाया जा सकता है, और compile time पर call की जाँच भी होती है
      वास्तव में Clojure core भी spec से macro calls की जाँच करता है, इसलिए गलत call होने पर कभी-कभी stack trace में उसका निशान दिखता है। जानना चाहता हूँ कि आपका मतलब कुछ और था क्या
  • यह बहुत अच्छा है कि इतनी सारी नई features आने के बावजूद पुराना code वैसे ही चलता है। breaking changes से बचने की लगातार कोशिश साफ दिखती है

  • अगर आप Clojure के बारे में और जानना चाहते हैं, तो 23–25 अक्टूबर को Alexandria, Virginia में होने वाले Clojure/conj conference पर नज़र डाल सकते हैं: https://2024.clojure-conj.org

  • add-libs और sync-deps का आना अच्छा लगा। अब session को ज़बरदस्ती बंद करने की वजह लगभग नहीं बची, या शायद बिल्कुल भी नहीं
    यह रिलीज़ scope के लिहाज़ से पिछली releases से काफी अलग लगती है, और इसमें बहुत कुछ जोड़ा गया है, इसलिए यह दिलचस्प है। बस उम्मीद है कि तेज़ रफ़्तार की वजह से कुछ releases बाद यह उलझा हुआ ढेर न बन जाए

    • Rich Hickey और Clojure Team बहुत सावधान designers हैं, इसलिए मुझे नहीं लगता कि ज़्यादा चिंता की ज़रूरत है
    • यह पूरी तरह अनुमान है, लेकिन चूँकि Rich Hickey के nubank छोड़ने के बाद यह पहली release है, हो सकता है वे इस पर ज़्यादा ध्यान दे पाए हों
  • functional interface बदलाव बहुत बड़ा है। Clojure तब सबसे अच्छा लगता है जब वह सोच-समझकर की गई interop के साथ Java के करीब रहता है, और इस बदलाव ने एक बड़ी कमी को भर दिया है

  • सोच रहा हूँ spec का क्या हुआ। क्या उसे छोड़ दिया गया है? कोई उत्साहजनक खबर है क्या

    • spec अभी भी मौजूद है और इस्तेमाल में है। उसके आगे का काम भी काफी हुआ है, लेकिन कई मुद्दों पर क्या करना है यह तय करते समय वह रुका हुआ है
  • यह एक काफी ठोस release लगती है, और यह देखकर खुशी होती है कि Clojure अभी भी अच्छा कर रहा है

    • जिज्ञासा है कि क्या यह सचमुच इतना अच्छा कर रहा है। मैं इसे नए project में इस्तेमाल करने के लिए evaluate कर रहा हूँ, और Clara[0] के साथ इसे consider कर रहा हूँ। लेकिन लगता है कि यह पहले जितना mainstream नहीं रहा, और ecosystem भी पहले से कुछ ज़्यादा sparse महसूस होता है
      मैं trolling नहीं कर रहा। मैं इसे चुनना चाहता हूँ, और engineering के नज़रिए से यह अच्छा निर्णय लगता है। लेकिन अगर popularity और contributors तेज़ी से गिर रहे हैं, तो निकट भविष्य में यह रुकावट बन सकता है
      [0] https://www.clara-rules.org/
  • मौजूदा developers को Clojure developers में बदलना अब पहले से कहीं आसान हो गया है
    शुरुआत में आने वाली बड़ी समस्या[0] code पढ़ना होती है, और ChatGPT या Claude जैसे AI मौजूदा Clojure code को समझाने में बहुत अच्छे हैं। नतीजतन developer onboarding काफ़ी तेज़ हो सकता है
    [0] कुछ हफ़्तों बाद Clojure पढ़ना स्वाभाविक लगने लगता है, और आप यह भी भूल जाते हैं कि पहले आप इसे पढ़ नहीं पाते थे

  • बहुत-से शानदार improvements हैं। यह आम तौर पर वह Lisp family language है जिसकी ओर मेरा हाथ सबसे पहले बढ़ता है