TIL #Clojure :reload-ing when :require-ing
eval
Tags: #Clojure, #TIL, #Babashka
When using Babashka I often add libraries like babashka/fs and bahaska/http-client as separate dependencies despite them being shipped with Babashka.
This 'version pinning' allows for using vars that are not necessarily in the latest bb
, or (when creating something for public consumption) makes the code compatible with an older version of bb
.
What you shouldn't forget when adding a library that also ships with bb
, is to :reload
when requiring a namespace from said library:
(ns bb.my-project
(:require [clojure.string :as string]
[babashka.fs :as fs] :reload ;; <-
[clojure.set :as set]))
;; Use recently introduced var
(prn #'fs/gunzip)
Because you often see the reload-flag right after some namespace, like in the example above, I was under the impression that it reloads that specific namespace.
But nope, turns out that it ensures all namespaces in the require-clause are reloaded.
This can be demonstrated by using the :verbose
flag that Clojure supports (another TIL):
$ clojure -M -e "(require '[clojure.set] '[clojure.data])
(require '[clojure.set] :reload
'[clojure.data] :verbose)"
# prints:
# (clojure.core/load "/clojure/set")
# (clojure.core/load "/clojure/data")
Both set
and data
are reloaded. Without :reload
this wouldn't print anything.
The reason I ran into this: requiring a Babashka pod in a require-clause that contains a :reload
won't work:
;; bb.edn
{:paths ["bb"]
:pods {org.babashka/go-sqlite3 {:version "0.1.0"}}}
;; bb/my_project/db.clj
(ns my-project.db
(:require [pod.babashka.go-sqlite3 :as sqlite]
[babashka.fs :as fs] :reload))
(defn -main [& _args]
(prn (sqlite/query ":memory:" ["SELECT 1 + 1 AS sum"])))
The error is similar to what happens when requiring the pod without adding it to bb.edn
:
$ bb -m my-project.db
----- Error --------------------------------------------------------------------
Type: java.io.FileNotFoundException
Message: Could not locate pod/babashka/go_sqlite3.bb, pod/babashka/go_sqlite3.clj or pod/babashka/go_sqlite3.cljc on classpath.
Location: /Users/gert/projects/playground/bb/pods/bb/my_project/db.clj:2:3
----- Context ------------------------------------------------------------------
1: (ns my-project.db
2: (:require [pod.babashka.go-sqlite3 :as sqlite]
^--- Could not locate pod/babashka/go_sqlite3.bb, pod/babashka/go_sqlite3.clj or pod/babashka/go_sqlite3.cljc on classpath.
3: [babashka.fs :as fs] :reload))
So the fix is to have a separate require-clause containing the reload:
(ns my-project.db
(:require [pod.babashka.go-sqlite3 :as sqlite])
(:require :reload
[babashka.fs :as fs]))
The Clojure styleguide doesn't touch on it, but I find it helpful to put the :reload
right after :require
to make the intent of the separate clause clearer.
Thanks
🌸 Thanks to Michiel aka borkdude for instantly recognising what was going on and helping me out on Clojurians Slack.
If you like my content, please consider supporting me with a paid Subscription.