March & April 2024 Long-Term Project Updates
By Kathy Davis
Our 2024 long-term developers report on an incredible body of work for March and April. A heartfelt thanks to all!
Bozhidar Batsov: CIDER
Michiel Borkent: squint, neil, clj-kondo,nbb, CLI, and more
Toby Crawley: clojars-web
Thomas Heller: shadow-cljs
Kira McLean: Scicloj Libraries and more
Nikita Prokopov: Datascript, Clj-reload, Clojure Sublimed, and more
Tommi Reiman: Reitit 7.0. Malli
Peter Taoussanis: http-kit, Nippy, Telemere, and more
Bozhidar Batsov
The biggest news in the past couple of months is that CIDER now supports clj-reload, as an alternative of clojure.tools.namespace! You can find the relevant PR here.
Some other noteworthy changes:
- Introduced support for global CLI aliases (more details)
- Many small improvements to the Inspector (see Orchard’s changelog, e.g. this section)
- Dropped support for Clojure 1.9 (it’s barely used these days and dropping it allows us to simplify the codebase and provide a better user experience)
- The inspector and code reloading now have dedicated pages in the CIDER’s docs:
Interested people should check out the recent changes in cider-nrepl and orchard, as that’s where the bulk of the work has happened.
We’ve yet to release a new version of CIDER, but I’m expecting this will happen before the end of May.
P.S. We might be close to a solution for the broken interrupt
functionality in nREPL on newer JDKs (20+). See this for details.
Michiel Borkent
Updates In this post I’ll give updates about open source I worked on during March and April 2024. To see previous OSS updates, go here.
Sponsors
I’d like to thank all the sponsors and contributors that make this work possible. Without you, the below projects would not be as mature or wouldn’t exist or be maintained at all.
Current top tier sponsors:
Sponsor info
If you want to ensure that the projects I work on are sustainably maintained, you can sponsor this work in the following ways. Thank you!
- Github Sponsors
- The Babaska or Clj-kondo OpenCollective
- Ko-fi
- Patreon
- Clojurists Together
If you’re used to sponsoring through some other means which isn’t listed above, please get in touch.
On to the projects that I’ve been working on!
Updates
Here are updates about the projects/libraries I’ve worked on last month.
-
squint: CLJS syntax to JS compiler
- #509: Optimization: use arrow fn for implicit IIFE when possible
- Optimization: emit
const
in let expressions, which esbuild optimizes better - Don’t wrap arrow function in parens, see this issue
- Fix #499: add support for emitting arrow functions with
^:=>
metadata - Fix #505: Support
:rename
in:require
- Fix #490: render css maps in html mode
- Fix #502: allow method names in
defclass
to override squint built-ins - Fix #496: don’t wrap strings in another set of quotes
- Fix rendering of attribute expressions in HTML (should be wrapped in quotes)
- Compile destructured function args to JS destructuring when annotated with
^:js
. This benefits working with vitest and playwright. - #481: BREAKING, squint no longer automatically copies all non-compiled files to the
:output-dir
. This behavior is now explicit with:copy-resources
, see docs. - Add new
#html
reader for producing HTML literals using hiccup. See docs and playground example. - #483: Fix operator precedence problem
-
neil: A CLI to add common aliases and features to deps.edn-based projects.
Released version 0.3.65 with the following changes: -
clj-kondo: static analyzer and linter for Clojure code that sparks joy.
Released 2024.03.13- Fix memory usage regression introduced in 2024.03.05
- #2299: Add documentation for
:java-static-field-call
. - #1732: new linter:
:shadowed-fn-param
which warns on using the same parameter name twice, as in(fn [x x])
- #2276: New Clojure 1.12 array notation (
String*
) may occur outside of metadata - #2278:
bigint
in CLJS is a known symbol inextend-type
- #2288: fix static method analysis and suppressing
:java-static-field-call
locally - #2293: fix false positive static field call for
(Thread/interrupted)
- #2296: publish multi-arch Docker images (including linux aarch64)
- #2295: lint case test symbols in list
Unreleased changed: - #1035: Support SARIF output with
--config {:output {:format :sarif}}
- #2309: report unused for expression
- #2135: fix regression with unused JavaScript namespace
- #2302: New linter:
:equals-expected-position
to enforce expected value to be in first (or last) position. See docs - #2304: Report unused value in
defn
body
-
CLI: Turn Clojure functions into CLIs!
Released version 0.8.58-59 -
rewrite-edn: Utility lib on top of rewrite-clj with common operations to update EDN while preserving whitespace and comments
Released 0.4.8 with the following update:- Add newline after adding new element to top level map with
assoc-in
- Add newline after adding new element to top level map with
-
nbb: Scripting in Clojure on Node.js using SCI
- nbb bundle JS output will ignore
nbb.edn
- #351: Update bun docs/example.
- Add
cljs.core/exists?
- nbb bundle JS output will ignore
-
clojure-mode: Clojure/Script mode for CodeMirror 6.
- Fix #49: bug with hitting backspace after line comment Test it in the squint playground.
-
instaparse-bb: Use instaparse from babashka
- Serialize regexes in parse results
-
scittle: Execute Clojure(Script) directly from browser script tags via SCI
Released v0.6.17 -
cherry: Experimental ClojureScript to ES6 module compiler
- #127: fix duplicate
cherry-cljs
property inpackage.json
which caused issues with some bundlers - Bump squint common compiler code
- #127: fix duplicate
-
- #646 Fix parsing + location issue which fixes compatibility with honey.sql
-
http-client: babashka’s http-client
Released 0.4.17-19 -
bbin: Install any Babashka script or project with one command
These fixes have been made by @rads: -
SCI: Configurable Clojure/Script interpreter suitable for scripting and Clojure DSLs
-
deps.clj: A faithful port of the clojure CLI bash script to Clojure
- Fix Windows issue related to relative paths (which took me all day, argh!)
-
fs - File system utility library for Clojure
-
babashka: native, fast starting Clojure interpreter for scripting.
- Fix #1679: bump timbre and fix wrapping
timbre/log!
- Add
java.util.concurrent.CountDownLatch
- Add
java.lang.ThreadLocal
- Bump versions of included libraries
- Fix #1679: bump timbre and fix wrapping
Other projects
There are many other projects I’m involved with but that had little to no activity in the past month. Check out the Other Projects section (more details) of my blog here to see a full list.
Published: 2024-04-30
Tagged: clojure oss updates
Toby Crawley
April 2024
Commit Logs: clojars-web
Mostly maintenance work this month related to error handling and tighening error boundaries.
- Tighten search page error handling
- Address CVEs with bouncycastle
- Remove usage of clj-time in favor of java.time
- Remove /error route
- Fix logback to actually roll logs
- Reject non-flat http params in an attempt to reduce errors from fuzzing
- Return invalid params response as json
March 2024
Commit Logs: clojars-web
, infrastructure
- Upgrade from Amazon Linux 2 to Amazon Linux 2023
- Updates to error handling and reporting to allow more to be reported
- Upgrades to address CVEs
Thomas Heller
Time was mostly spent on doing maintenance work and some bugfixes. As well as helping people out via the typical channels (e.g. Clojurians Slack).
Current shadow-cljs version: 2.28.4 Changelog
Notable Updates
- Introduced the shadow-cljs Browser Extension
- Worked on some additional devtools for shadow-grove, which will also end up as a browser extension at some point. Similar in spirit as the react/vue developer tools.
Kira McLean
This is a summary of the open source work I’ve spent my time on throughout March and April, 2024. Overall it was a really insightful couple of months for me, with lots of productive discussions and meetings happening among key contributors to Clojure’s data science ecosystem and great progress toward some of our most ambitious goals.
Sponsors
This work is made possible by the generous ongoing support of my sponsors. I appreciate all of the support the community has given to my work and would like to give a special thanks to Clojurists Together and Nubank for providing me with lucrative enough grants that I can reduce my client work significantly and afford to spend more time on these projects.
If you find my work valuable, please share it with others and consider supporting it financially. There are details about how to do that on my GitHub sponsors page. On to the updates!
Grammar of graphics in Clojure
With help from Daniel Slutsky and others in the community, I started some concrete work on implementing a grammar of graphics in Clojure. I’m convinced this is the correct long-term solution for dataviz in Clojure, but it is a big project that will take time, including a lot of hammock time. It’s still useful to play around with proofs of concept whilst thinking through problems, though, and in the interest of transparency I’m making all of those experiments public.
The discussions around this development are all also happening in public. There were two visual tools meetups focused on this over the last two months (link 1, link 2). And at the London Clojurians talk I just gave today I demonstrated an example of one proposed implementation of a grammar-of-graphics-like API on top of hanami implemented by Daniel.
There are more meetups planned for the coming months and work in this area for the foreseeable future will look like researching and understanding the fundamentals of the grammar of graphics in order to design a simple implementation in Clojure.
Clojure’s ML and statistics tools
I spent a lot of time these last couple of months documenting and testing out Clojure’s current ML tools, leading to many great conversations and one blog post that generated many more interesting discussions. The takeaway is that the tools themselves in this area are all quite mature and stable, but there are still ongoing discussions around how to best accommodate the different ways that people want to work with them. The overall goal in this area of my work is to stabilize the solutions so we can start advocating for specific ways of using them.
Below are some key takeaways from my research into all this stuff. Note none of these are my decisions to make alone, but represent my current opinions and what I will be advocating for within the community:
- Smile will be slowly sunsetted from the ecosystem. The switch to GPL licensing was made in bad faith and many of the common models don’t work on Apple chips. Given the abundance of suitable alternatives, the easiest option is to move away from depending on it.
- A greater distinction between statistical modelling and machine learning workflows will be helpful. Right now there are many uses of the various models that are available in Clojure, and the wrappers and tools surrounding them are usually designed with a specific type of user in mind. For example machine learning people almost always have separate training and testing datasets, whereas statisticians “train” their models on an entire dataset. The highest-level APIs for these different usages (among others) look quite different, and we would benefit from having APIs that are ergonomic and familiar to our target users of various backgrounds.
- We should agree on standards for accomplishing certain very common and basic tasks and propose a recommended usage for users. For example, there are almost a dozen ways to do linear regression in Clojure and it’s not obvious which is “the best” way to someone not deeply familiar with the ecosystem.
- Everything should work with tablecloth datasets and expect them as inputs. This is mostly the case already, but there is still some progress to be made.
Foundations of Clojure’s data science stack
I continue to work on guides and tutorials for the parts of Clojure’s data science stack that I feel are ready for prime time, mainly tablecloth and all of the amazing underlying libraries it leverages. Every once in a while this turns up surprises, for example this month I was surprised at how column header processing is handled for nippy files specifically. I also fixed one bug in tablecloth itself, which I discovered in the process of writing a tutorial earlier in March. I have a pile of in-progress guides focusing on some more in-depth topics from developing the London Clojurians talk that I’m going to tidy up and publish in the coming months.
The overarching goal in this area is to create a unified data science stack with libraries for processing, modelling, and visualization that all interoperate seamlessly and work with tablecloth datasets, like the tidyverse in R. Part of achieving that is making sure that tablecloth is rock solid, which just takes a lot of poking and prodding.
London Clojurians talk
This talk was a big inspiration for diving deep into Clojure’s data science ecosystem. I experimented with a ton of different datasets for the workshop and discovered tons of potential areas for future development. Trying to put together a polished data workflow really exposed many of the key areas I think we should be focusing on and gave me a lot of inspiration for future work. I spent a ton of time exploring all of the possible ways to demonstrate a broad sample of data science tools and learned a lot along the way.
The resources from the talk are all available in this repo and the video will be posted soon.
Summary of future work
I mentioned a few areas of focus above, below is a summary of the ongoing work as I see it. A framework for organizing this work is starting to emerge, and I’ve been thinking about in terms of four key areas:
Visualisation
- Priority here is to release a stable dataviz API using the tools and wrappers we currently have so that we can start releasing guides and tutorials that follow a consistent style.
- The long-term goal is to develop a robust, flexible, and stable data visualization library in Clojure itself based on the grammar of graphics.
Machine learning
- Priority is to decide which APIs we will commit to supporting in the long term and stabilize the “glue” libraries that provide the high-level APIs for data-first users.
- Long term goal is to support the full spectrum of libraries and models that are in everyday use by data science professionals.
Statistics
- Priority is to document the current options for accomplishing basic statistical modelling tasks, including Clojure libraries we do have, Java libs, and Python interop.
- Long term goal is to have tablecloth-compatible stats libraries implemented in pure Clojure.
Foundations
- Priority is to build a tidyverse for Clojure. This includes battle-testing tablecloth, fully documenting its capabilities, and fixing remaining, small, sharp edges.
Going forward
My overarching goal (personally) is still to write a canonical resource for working with Clojure’s data science stack (the Clojure Data Cookbook), and I’m still working on finding the right balance of documenting “work-in-progress” tools and libraries vs. delaying progress until I feel they are more “ready”. Until now I’ve let the absence of stable or ideal APIs in certain areas hinder development of this book, but I’m starting to feel very confident in my understanding of the current direction of the ecosystem, enough so that I would feel good about releasing something a little bit more formal than a tutorial or guide and recommending usages with the caveat that development is ongoing in some areas. And while it will take a while to get where we want to go, I feel like I can finally see the path to getting there. It just takes a lot of work and lot of collaboration, but with your support we’ll make it happen! Thanks for reading.
Nikita Prokopov
Hello hello hello, I hope you like some open-source, because I have some for ya. This past two months have been busy!
- Implement “constant substitution” optimization for queries #462
- Fixed :max-eid for dangling entities during reader-based serialization #463
- Fixed tempid in unique refs #464
- Pass through BigInteger/BigDeciman to freeze-fn in serializable #465, #466
- Migration to VDOM continues. Ported
stack
, redidbutton
- Redid state sharing approach between behavior components (e.g.
clickable
) and visual ones (e.g.button-look
) - New frame & event pace graphs
- New canvas example (drawing, mouse lag graph)
- Surface and PictureRecorder cache returned Canvas object and invalidate it when owner is closed #66
clj-reload, a smarter way to reload Clojure code:
- Added
unload
- Fixed issues when adding/removing keeps
- Speed up topo-sort #5
- Do not report self-reference as a cycle #6
- Parse record ctor syntax #7
- Added
:files
option #8
Clojure Sublimed, Clojure development environment for Sublime Text:
- Socket REPL: Watches (just like in original LightTable!)
- Added
transform
argument toclojure_sublimed_eval
. It lets you implement stuff like print to buffer, eval test under cursor, macroexpand etc #101 #102 - Added
expand
argument toclojure_sublimed_eval
- Added
output.repl
panel andToggle Output Panel
command for raw nREPL #104 - Raw nREPL: Support colored output in output console #99
- Display failed tests report as red
- Fixed
Reconnect
command - Add
on_finish_callback
toeval
#105 - Added
print_quota
as a setting and as an argument tocs_conn.eval
New library: sane-math
- Write mathematical expression in Clojure in infix notation
- Part April Fools’ joke, part serious
- Supports
+
,−
,*
,/
, unary minus,**
and parentheses
Blogging:
- Hardest Problem in Computer Science: Centering Things
- Humble Chronicles: The Inescapable Objects
- Humble Chronicles: Shape of the Component
- Daylight Saving Time is a perfect test for UI designer
Best,
Niki
Tommi Reiman
Finally! Reitit 0.7.0 is out. It has been over a year in the making, spanning multiple libraries: reitit, malli, schema-tools, [spec-tools](https://github.com/metosin/spec-tools and ring-swagger-ui. Big thanks to everyone involved. There is a lot of draft work that has been queued and can now be worked on. New releases should come more frequently in the future.
Reitit 0.7.0 (all 8 alphas flattened)
0.7.0 (2024-04-30)
The OpenAPI3 release, Year in the making - the changes span over multiple repositories!
-
Openapi3 support, see the docs
- Fetch OpenAPI content types from Muuntaja #636
- OpenAPI 3 parameter descriptions get populated from malli/spec/schema descriptions. #612
- Generate correct OpenAPI $ref schemas for malli var and ref schemas #673
- new syntax for
:request
and:response
per-content-type coercions. See coercion.md. #627 - #84
-
Handlers can be vars #585
-
Fix swagger generation when unsupported coercions are present #671
-
BREAKING: require Clojure 1.11, drop support for Clojure 1.10
-
BREAKING:
compile-request-coercers
returns a map with:data
and:coerce
instead of plain:coerce
function -
BREAKING: Parameter and Response schemas are merged into the route data vector - so they can be properly merged into the compiled result, fixes #422 - merging multiple schemas together works with
Malli
andSchema
, partially withdata-spec
but not withspec
. -
Fixed some module dependencies so Cljdoc can properly analyze all the modules
-
Fix reading fragment string on
Html5History
initialization -
Add fragment string parameter to reitit-frontend functions (#604)
-
Frontend: provide easy way to update current query params. #600
-
Updated dependencies:
[metosin/malli "0.16.1"] is available but we use "0.10.1"
[metosin/muuntaja "0.6.10"] is available but we use "0.6.8"
[metosin/spec-tools "0.10.6"] is available but we use "0.10.5"
[metosin/schema-tools "0.13.1"] is available but we use "0.13.0"
[metosin/jsonista "0.3.8"] is available but we use "0.3.7"
[com.fasterxml.jackson.core/jackson-core "2.17.0"] is available but we use "2.14.2"
[com.fasterxml.jackson.core/jackson-databind "2.17.0"] is available but we use "2.14.2"
[ring/ring-core "1.12.1"] is available but we use "1.9.6"
[metosin/ring-swagger-ui "5.9.0"] is available but we use "4.15.5"
Malli
0.16.1 (2024-04-30)
- Enabled Java8 tests back, no need to limit the version.
0.16.0 (2024-04-20)
- BREAKING: minimum Java-version is now Java11
- allow changing prefix of json-schema $refs via option
:malli.json-schema/definitions-path
#1045 - Inline refs in non-
:body
swagger parameters #1044 - Fix flaky test #1040
- Utility to update entry properties:
mu/update-entry-properties
#1037 - Fix actions cache #1036
- Only humanize one of
:min
/:max
when different #1032 - Distinguish between symbols and strings in humanize #1031
- Fix
:map-of
:min
and unreachable generator, explain such-that failures #1029
0.15.0 (2024-03-23)
:=>
takes optional 3rd child, the guard schema validating vector of arguments and return value[args ret]
. See Function Guards for more details. Fixes #764 and #764.
;; function of arg:int -> ret:int, where arg < ret
[:=>
[:cat :int]
:int
[:fn (fn [[[arg] ret]] (< arg ret))]]
-
BREAKING:
malli.generator/function-checker
returns explanations under new keys:::mg/explain-input
->::m/explain-input
::mg/explain-output
->::m/explain-output
- new
::m/explain-guard
to return guard explanation, if any
-
m/explain
for:=>
returns also errors for args, return and guard if they exist -
FIX
m/deref-recursive
doesn’t play nice with:merge
schema #997 via #999 -
FIX nested
:repeat
sequence schema’s doesn’t seem to work #761 via #1024 -
FIX Invalid Swagger JSON with
[:or :nil]
alternatives #1006 via #1023 -
FIX
(explain :tuple [])
#1022 -
Enforce entry specs in open map destructurings #1021
-
FIX
goog/mixin
was deprecated and is now removed #1016 -
Updated dependencies:
borkdude/edamame 1.3.23 -> 1.4.25
Something else
Back at Greece, to relax and to Open Source.
Peter Taoussanis
A big thanks to Clojurists Together, Nubank, lambdaschmiede, and other sponsors of my open source work!
Hi folks! 🦎
It’s been a very productive couple months! Have been able to continue full-time on open source. Output included:
http-kit v2.8.0
http-kit v2.8.0 final is now on Clojars 👍
http-kit is a simple, high-performance event-driven HTTP client+server for Clojure.
This is the first major stable http-kit release since 2023-06-30, and includes work from 10 contributors. Big thanks to everyone involved! 🙏
Some highlights include:
- Performance improvements, incl. auto JVM 21+ virtual threads when available.
- Support for the latest Ring async and WebSocket APIs.
- A comprehensive new benchmark suite for http-kit server and client.
- >15 fixes and numerous other improvements
Nippy v3.4.0
Nippy v3.4.0 final is now on Clojars 👍
Nippy is a fast and mature binary serialization library for Clojure.
This is the first major stable Nippy release since 2023-10-11, and includes:
- Faster, more accurate freezable? util (checks if arg is serializable)
- Zstandard compression support
- Support for serializing next.JDBC results (this was previously broken)
Telemere v1.0.0 first public pre-releases
My main focus during this period has been has been Telemere.
Telemere is a major new library (and along with Tempel, my first all-new library in 7+ years). It’s a structured telemetry library for Clojure/Script, and a highly-polished modern rewrite of Timbre without any of the historical constraints.
It offers a superset of the functionality found in traditional and structured logging, and out-the-box support for SLF4J, OpenTelemetry, clojure.tools.logging, etc.
The latest release can be found here (currently beta5).
Folks happy with Timbre have zero pressure to update, I’ll continue to support Timbre as usual. But Telemere offers a lot of new features and improvements (see README), and migration is often pretty easy.
Will note that based on Clojure survey feedback, I’ve been putting a lot more emphasis lately on beginner-oriented support. For Telemere this includes the most comprehensive wiki and API docs I’ve yet included with a library.
Please do let me know if this stuff is helpful, since it adds a lot to the development effort! 🙏
There’s also a new Telemere Slack channel and short demo video.
Telemere’s a small library, but it’s been a lot of work getting the details just right. I’m happy with the results, and excited for folks to try it out.
Telemere is in many ways represents the refinement and culmination of ideas brewing over 12+ years in Timbre, Tufte, Truss, etc.
Ultimately the hope is for it to help enable Clojure/Script systems that are observable, robust, and debuggable. The wiki intro is probably a good place to start if you’re interested in hearing more.
London Clojurians talk
This was actually recorded back in February, but I have folks still occasionally mentioning that they’d missed it earlier - so I’ll share a reminder here.
The talk is available on YouTube, and is titled Some Controversial Truths: _challenging some commonly-held ideas about Clojure, software engineering, and startups; and sharing the 1 secret that will solve all your problems.
Big thanks to Bruno Bonacci for hosting!
Interview with Daniel Compton
Likewise for folks that missed it earlier - Daniel Compton recently posted a chat we had about my open source work. Big thanks to Daniel for hosting!
Upcoming work
My current roadmap can always be found here.
Current objectives for May-June include:
-
Release the final stable version of Tempel - my new data security framework for Clojure. Before the final release I’m planning to add support for MFA, extend the docs re: use with OpenID, OWASP, and make a few other last improvements.
-
Continued efforts on Telemere. I’m currently working on porting handlers over from Timbre, improving the documentation, and helping out folks on the Slack channel.
-
(If time allows) I’d also like to update Tufte to use the new engine that was written for Telemere. The two already work well together, but this’ll be especially true after they share the same engine (and so filtering and handler API).