28 April 2024
Alex Miller
Clojure 1.12.0-alpha10 is now available! Find download and usage information on the Downloads page.
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 Java qualified methods as ordinary functions in value contexts - the compiler will automatically generate the wrapping function. New in this release: 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.
New in this release: the compiler will generate a reflective call when param tags are not supplied on a qualified method that does not resolve due to overloading.
Class/method
, Class/.method
, and Class/new
Java members inherently exist in a class. For methods as 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
New in this release: 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.
See: CLJ-2844
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 ^[ … ]
attaches :param-tags
metadata to member symbols, just as ^tag
attaches :tag
metadata to a symbol.
See: CLJ-2805
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
.
See: CLJ-2807
CLJ-2843 - Reflective calls to Java methods that take primitive long or double now work when passed a narrower boxed number at runtime (Integer, Short, Byte, Float). Previously, these methods were not matched during reflection and an error was thrown.
CLJ-2841 - IDeref should also implement DoubleSupplier