Static-Free ClojureScript REPL
The general advice is to leave :static-fns
turned off for development with the ClojureScript REPL.
If you are curious and turn it on, most things will work anyway. This post gives a concrete example illustrating what can go wrong if you do turn it on.
Let's say you have a multi-arity function f
(defn f
([a]
(prn a))
([a b]
(prn a b)))
and you define another function g
that calls it:
(defn g
[]
(f 1 2))
If you try (g)
at the REPL, it will print 1 2
.
Now, let's say you revise f
to be variadic:
(defn f
([a]
(prn a))
([a & [b]]
(prn a b)))
With this change, (g)
will still print 1 2
as expected.
But, let's try this with :static-fns
set to true
. Try it with your favorite ClojureScript REPL.
If you want to try this with Planck, you can simply re-launch it passing
-s
or--static-fns
as described in Planck Static Function Dispatch.
If you go through the same sequence, you will get an error indicating the following when you evaluate (g)
the second time:
cljs.user.f.cljs$core$IFn$_invoke$arity$2 is not a function.
This is the static dispatch to the 2-arity version of f
.
If you reverse the order of the definition of f
and g
, you will then get the opposite error:
cljs.user.f.cljs$core$IFn$_invoke$arity$variadic is not a function.
You can see these dispatch mechanisms statically embedded in the definition of g
if you look at its emitted JavaScript.
On the other hand, if you have :static-fns
disabled, then the code emitted for g
will involve
cljs.user.f.call(null,(1),(2))
which works under the re-definition of f
.
While this dispatch mechanism is slower, it affords you the dynamic-dispatch Lispy flexibility you take for granted while redefining things at the REPL.