Clojure 1.12.0 现已推出 Clojure 1.12.0 is now available

原始链接: https://clojure.org/news/2024/09/05/clojure-1-12-0

Clojure 在 1.12.0-alpha1 版本中引入了多项改进。 以下是简要概述: 1. **交互式库**:它允许用户在不重新启动Java虚拟机(JVM)的情况下添加库,从而更容易地实验、测试或执行特定任务。 2. **进程外工具函数**:用户现在可以在主应用程序外部执行工具函数,即使它们不包含在项目的依赖项中。 此功能对于开发目的特别有用。 3. **方法值**:开发人员现在可以更轻松地在高阶函数中使用 Java 方法,而无需编写包装函数。 编译器自动生成所需的代码,消除不必要的冗长文字。 4. **带有参数标签的限定方法**:通过提供额外的元数据(参数标签),用户可以确保他们的首选方法在重载中正确解析。 此信息有助于编译器在编译时选择适当的方法。 5. **数组类语法**:Clojure 现在提供了引用数组类的语法,允许开发人员更直观地处理数组。 6. **流支持**:针对 Java 流的使用进行了增强,通过“stream-seq”、“stream-reduce”和“stream-transduce”等专用功能提​​供改进的兼容性和更平滑的集成。 7. **高效删除和分区**:从持久或算法集合中删除元素和分区数据的改进使操作更快、更高效。 8. **Var Interning 策略**:更新确保变量 (var) 一旦被驻留在命名空间中,它就保持稳定并且不会被替换; 从而在整个系统中产生一致的引用。 总的来说,这些变化旨在提高编写 Clojure 应用程序时的生产力、可读性和效率。

Clojure has introduced several improvements in version 1.12.0-alpha1. Here's a brief overview: 1. **Interactive Libraries**: It allows users to add libraries without restarting the Java Virtual Machine (JVM), making it easier to experiment, test or perform specific tasks. 2. **Out-of-process Tool Functions**: Users can now execute tool functions outside the main application, even if they aren't included in the project's dependencies. This feature is particularly useful for development purposes. 3. **Method Values**: Developers can now utilize Java methods within higher-order functions more easily without needing to write wrapper functions. The compiler generates the required code automatically, eliminating unnecessary verbiage. 4. **Qualified Methods with Param-Tags**: By providing additional metadata (Param-tags), users can ensure that their preferred method is resolved correctly among overloads. This information helps the compiler select the appropriate method at compilation time. 5. **Array Class Syntax**: Clojure now offers syntax for referring to array classes, allowing developers to handle arrays more intuitively. 6. **Stream Support**: Enhancements have been made for working with Java streams, offering improved compatibility and smoother integration through dedicated functions such as `stream-seq`, `stream-reduce` and `stream-transduce`. 7. **Efficient Drop and Partition**: Improvements to dropping elements and partitioning data from persistent or algorithmic collections make operations faster and more memory-efficient. 8. **Var Interning Policy**: Updates ensure that once a variable (var) is interned in a namespace, it remains stable and won't be replaced; resulting in consistent references across the entire system. Overall, these changes aim to improve productivity, readability, and efficiency when writing Clojure applications.


2.1 Add libraries for interactive use

There are many development-time cases where it would be useful to add a library interactively without restarting the JVM - speculative evaluation, adding a known dependency to your project, or adding a library to accomplish a specific task.

  • add-lib takes a lib that is not available on the classpath, and makes it available by downloading (if necessary) and adding to the classloader. Libs already on the classpath are not updated. If the coordinate is not provided, the newest Maven or git (if the library has an inferred git repo name) version or tag are used.

  • add-libs is like add-lib, but resolves a set of new libraries and versions together.

  • sync-deps calls add-libs with any libs present in deps.edn, but not yet present on the classpath.

These new functions are intended only for development-time interactive use at the repl - using a deps.edn is still the proper way to build and maintain production code. To this end, these functions all check that *repl* is bound to true (that flag is bound automatically by clojure.main/repl). In a clojure.main REPL, these new functions are automatically referred in the user namespace. In other repls, you may need to (require '[clojure.repl.deps :refer :all]) before use.

Library resolution and download are provided by tools.deps. However, you do not want to add tools.deps and its many dependencies to your project classpath during development, and thus we have also added a new api for invoking functions out of process via the Clojure CLI.

2.2 Invoke tool functions out of process

Clojure now includes clojure.tools.deps.interop/invoke-tool to invoke a tool function out of process. The classpath for the tool is defined in deps.edn and you do not need to add the tool’s dependencies to your project classpath.

add-lib functionality is built using invoke-tool but you can also use it to build or invoke your own tools for interactive use. Find more about the function execution protocol on the CLI reference.

2.4 Method values

Clojure programmers often want to use Java methods in higher-order functions (e.g. passing a Java method to map). Until now, programmers have had to manually wrap methods in functions. This is verbose, and might require manual hinting for overload disambiguation, or incur incidental reflection or boxing.

Programmers can now use qualified methods as ordinary functions in value contexts - the compiler will automatically generate the wrapping function. The compiler will generate a reflective call when a qualified method does not resolve due to overloading. Developers can supply :param-tags metadata on qualified methods to specify the signature of a single desired method, 'resolving' it.

2.5 Qualified methods - Class/method, Class/.method, and Class/new

Java members inherently exist in a class. For method values we need a way to explicitly specify the class of an instance method because there is no possibility for inference.

Qualified methods have value semantics when used in non-invocation positions:

  • Classname/method - value is a Clojure function that invokes a static method

  • Classname/.method - value is a Clojure function that invokes an instance method

  • Classname/new - value is a Clojure function that invokes a constructor

Note: developers must use Classname/method and Classname/.method syntax to differentiate between static and instance methods.

Qualified method invocations with :param-tags use only the tags to resolve the method. Without param-tags they behave like the equivalent dot syntax, except the qualifying class takes precedence over hints of the target object, and over its runtime type when invoked via reflection.

Note: Static fields are values and should be referenced without parens unless they are intended as function calls, e.g (System/out) should be System/out. Future Clojure releases will treat the field’s value as something invokable and invoke it.

2.6 :param-tags metadata

When used as values, qualified methods supply only the class and method name, and thus cannot resolve overloaded methods.

Developers can supply :param-tags metadata on qualified methods to specify the signature of a single desired method, 'resolving' it. The :param-tags metadata is a vector of zero or more tags: [tag …​]. A tag is any existing valid :tag metadata value. Each tag corresponds to a parameter in the desired signature (arity should match the number of tags). Parameters with non-overloaded types can use the placeholder _ in lieu of the tag. When you supply :param-tags metadata on a qualified method, the metadata must allow the compiler to resolve it to a single method at compile time.

A new metadata reader syntax ^[tag …​] attaches :param-tags metadata to member symbols, just as ^tag attaches :tag metadata to a symbol.

2.7 Array class syntax

Clojure supports symbols naming classes both as a value (for class object) and as a type hint, but has not provided syntax for array classes other than strings.

Developers can now refer to an array class using a symbol of the form ComponentClass/#dimensions, eg String/2 refers to the class of a 2 dimensional array of Strings. Component classes can be fully-qualified classes, imported classes, or primitives. Array class syntax can be used as both type hints and values.

Examples: String/1, java.lang.String/1, long/2.

2.10 Streams with seq, into, reduce, and transduce support

Java APIs increasingly return Streams and are hard to consume because they do not implement interfaces that Clojure already supports, and hard to interop with because Clojure doesn’t directly implement Java functional interfaces.

In addition to functional interface support, Clojure now provides these functions to interoperate with streams in an idiomatic manner, all functions behave analogously to their Clojure counterparts:

  • (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

All of these operations are terminal stream operations (they consume the stream).

2.12 Efficient drop and partition for persistent or algorithmic collections

Partitioning of a collection uses a series of takes (to build a partition) and drops (to skip past that partition). CLJ-2713 adds a new internal interface (IDrop) indicating that a collection can drop more efficiently than sequential traversal, and implements that for persistent collections and algorithmic collections like range and repeat. These optimizations are used in drop, nthrest, and nthnext.

Additionally, there are new functions partitionv, partitionv-all, and splitv-at that are more efficient than their existing counterparts and produce vector partitions instead of realized seq partitions.

2.13 Var interning policy

Interning a var in a namespace (vs aliasing) must create a stable reference that is never displaced, so that all references to an interned var get the same object. There were some cases where interned vars could get displaced and those have been tightened up in 1.12.0-alpha1. If you encounter this situation, you’ll see a warning like "REJECTED: attempt to replace interned var #'some-ns/foo with #'other-ns/foo in some-ns, you must ns-unmap first".

This addresses the root cause of an issue encountered with Clojure 1.11.0, which added new functions to clojure.core (particularly abs). Compiled code from an earlier version of Clojure with var names that matched the newly added functions in clojure.core would be unbound when loaded in a 1.11.0 runtime. In addition to CLJ-2711, we rolled back a previous fix in this area (CLJ-1604).

相关文章
联系我们 contact @ memedata.com