Fork me on GitHub

Could someone explain to me how do I tell that this function takes in 3 inputs? 😮

(require '[clojure.string :as string])

(def greetings
  (fnil string/replace "Nothing to replace" "Morning" "Evening"))

(greetings "Good Morning!" "Morning" "Evening") ;
;; "Good Evening!"
(greetings nil "Morning" "Evening")
;; "Nothing to replace"
(greetings "Good Morning!" nil "Evening")
;; "Good Evening!"

Ruy Valle03:08:15

The short answer is string/replace takes three inputs, and therefore greetings takes three inputs. fnil wraps the function it is given (in your case string/replace), returning a new function. This new function will pass along its arguments to the wrapped function, except it will replace nils in the first three arguments by the values provided when calling fnil. The function returned by fnil can take 2 or more inputs, but in your case it will fail if you give it any number of inputs other than 3, because string/replace takes exactly three arguments.

Ruy Valle03:08:12

user=> (greetings)
Execution error (ArityException) at user/eval9 (REPL:1).
Wrong number of args (0) passed to: clojure.core/fnil/fn--6902

user=> (greetings "a")
Execution error (ArityException) at user/eval11 (REPL:1).
Wrong number of args (1) passed to: clojure.core/fnil/fn--6902

user=> (greetings "a" "b")
Execution error (ArityException) at user/eval13 (REPL:1).
Wrong number of args (2) passed to: clojure.string/replace

user=> (greetings "Hello" "e" "u")
user=> (greetings "a" "b" "c" "d")
Execution error (ArityException) at user/eval20 (REPL:1).
Wrong number of args (4) passed to: clojure.string/replace

Ruy Valle03:08:48

notice Wrong number of args (…) passed to: clojure.core/fnil/fn--6902 (an anonymous function produced by fnil) vs. … passed to: clojure.string/replace


@zackteo Although Ruy already answered at length, one thing to remember is that you can (nearly) always see the source for library functions so you can see what is going on under the hood:

user=> (source fnil)
(defn fnil
... (shorter arities omitted)
  ([f x y z] ; <- this is how fnil is invoked in greetings...
   (fn ; ...and it returns a function of 2-or-more arguments:
     ([a b] (f (if (nil? a) x a) (if (nil? b) y b)))
     ([a b c] (f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c)))
     ([a b c & ds] (apply f (if (nil? a) x a) (if (nil? b) y b) (if (nil? c) z c) ds)))))
So we can see that greetings effectively has 2-arity, 3-arity, and 4+ arity implementations that will each call string/replace


As Ruy pointed out, if you try to call greetings with 0, 1, 2, or 4+ arguments, it will call the anonymous function returned by fnil, so for the 0 and 1 arity calls, it will fail because the returned function does not have that arity; for the 2, 3, and 4+ arities it will call f (i.e., string/replace) with the same number of arguments.

Pragyan Tripathi06:08:48

Hey Guys, I am trying send application configuration as an HTTP API response. In my case it looks like following:

(GET "/apps" []
      {:body {:com.vadelabs.bridge.profile/base
              {:com.vadelabs.bridge/project-ns '
               [#block/block []
                #block/block []]
              :com.vadelabs.bridge.profile/dev {}
              :com.vadelabs.bridge.profile/local {}
              :com.vadelabs.bridge.profile/prod {}
              :com.vadelabs.bridge.server/rest {}
              :com.vadelabs.bridge/logger {}}})
Now as soon as I added tagged literal #block/block The application starts failing with following error:
; Syntax error reading source at (com/vadelabs/studio/handler.clj:19:68).
; No reader function for tag block/block
Is there a way I can send these tagged literal to the client, The client would read it as per it’s implementation.


Hmmm... What are you trying to do? You may find it useful to use a templating thing like Selmer.

Anefu Favour09:08:37

Hello everyone, I'm trying to start a cljs project using shadow-cljs, but I keep getting Undertow Request Failed and OutOfMemory errors. I get the errors after I run npx shadow-cljs watch app, when I try to connect to the running server. Thank you!


if you don't get a response, you might also try #shadow-cljs


Thanks @seancorfield thanks - actually I thought for a moment you meant I could do something like (source greetings) thanks @ruyvalle too! Actually my mainly confusion was the six arguments. Like how this came to be ...

(greetings "Good Morning!" nil "Evening")
;; "Good Evening!"
But then I finally got why I was confused. I was thinking "Nothing to replace" "Morning" "Evening" were already arguments to string/replace but in actuality (greetings "Good Morning!" nil "Evening") just became (string/replace "Good Morning!" "Morning" "Evening") that was the part I was confused about. I understood what fnil was supposed to replace stuff when nil but it didn't click when I saw what I thought was 6 arguments with string/replace Thanks for your help!


Hi guys, I started to write a blog about my Clojure journey. More about it and the first post - about IDEs - here on reddit:

👍 2
Alexander G13:08:00

Hello everyone! I want to write application that will handle many events, so I wanted to use vertx for that, but I see that vertx dropped clojure support after vertx2. What do you think, current ring infrastructure (with undertow beneath, maybe) can handle such type of load efficiently? Or maybe better to use java interop here and write with vertx?

Shuai Lin01:08:49

What's the scale of your application, and have you confirmed that a thread pool based solution (e.g. jetty) really won't make it?

Alexander G11:08:41

Is it really depends on a scale? I cant predict a scale upfront for this app, but I thought it is better to pick the right tool from the start, and to not rewrite after