r/Clojure • u/alexdmiller • 27d ago
Clojure 1.13.0-alpha8 is now available
Selectors
A developer may need to apply the same key-selection logic embedded in a map destructuring form (as directives, :keys!/:syms!/:strs!/etc., nesting, etc.) against multiple maps, or want to hand that selection logic to another part of the program. Currently that logic is oriented around binding in destructuring and not for programmatic use.
This release adds a new selector macro that takes a destructuring form and returns a function that can be applied to maps:
(selector [m])
Builds a selecting-fn from m, a map destructuring form that must
include one or more of the :select, :all, :missing, and :excess
directives. The return function takes a collection, destructures it
per m, and returns a map of the result(s).
If m has exactly one directive, the result is the value that
directive would yield. If m has more than one directive, then it
returns a map of directives to values.
As in destructuring, :missing controls whether missing required keys
throw or are collected.
While a map destructuring form may and sometimes must include
bindings, selector doesn't produce bindings, thus ignoring the
associated directive names.
Throws an exception if the argument is not a map.
- CLJ-2979 selector
Transient map performance
This release contains many performance improvements around the use of maps, particularly transient maps, and functions like into, merge, and merge-with.
Transient array maps now grow larger before transitioning to transient hash maps (similar to recent persistent array map changes), and can be loaded significantly faster. The increased use of persistent and transient array maps will also make many more call sites inside the Clojure runtime monomorphic, encouraging greater JVM inlining. For more info see CLJ-2980.
Improvements and bug fixes
- CLJ-2939 QualifiedMethodExpr field overload does not propagate field type - fixed
- CLJ-1468 merge-deep, merge-deep-with - added recursive merge fns
- CLJ-2981 merge - added tests
- CLJ-2623 tagged literals and Java constructors - allow full unicode for first char
- CLJ-2623 tagged-literal equality - check tag before form for performance
- CLJ-2842 defn - does not needlessly initialize class when defn returns class
- CLJ-2896 clojure.zip/next - only call zip/up once (not 3x)
- CLJ-2915 ExceptionInfo - added to default imports, so no import or qualification needed
1
u/pragyantripathi 27d ago
Are there benchmarks for the transient map changes on into and merge with small maps? Curious how much of the gain comes from the higher array-map threshold versus faster loading.
3
u/alexdmiller 27d ago
I think the biggest improvement in TAM assoc is actually from the key-specific indexOf change - that’s actually the bottleneck. The metadata propagation was also significant. Lots of other incremental improvements.
3
u/lgstein 27d ago
I'm fairly confident that the :req stuff might turn out a significant game changer for the Clojure developer experience. I did something similar in march or so, writing a little declarative "lean ad hoc type DSL" - runtime checked - for certain frequently used top level domain constructors in a project. While the "type" stuff was less generalizable, the ":req" stuff made things so much better alone. Just "this key is.missing" instead of an obscure NPE (or unintended nil punning with unintended consequences) to be fished out/traced back from a stacktrace somewhere else. It is not so much about "correctness" claims, just reducing friction from miscommunication between programmer and computer in both directions. Very pragmatic. Looking forward to have this available cheaply and ad hoc in map destructoring without having to invest in a whole spec/type system with separate declarations and names etc.
2
u/lostcoffee 27d ago
re https://clojure.atlassian.net/browse/CLJ-2915: interesting. Because
clojure.lang.ExceptionInfowasn't exposed via Clojure, I've been treating it like an implementation detail and dealing withex-infos like(try ... (catch Exception e (if-let [data (ex-data e)] ... (throw e))))