Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create default value for function argument in Clojure

People also ask

Can a function argument have default value?

Once a default value is used for an argument in the function definition, all subsequent arguments to it must have a default value as well. It can also be stated that the default arguments are assigned from right to left.

What is default arguments in function give example?

The default value is given in the form of variable initialization. Example : void defaultvalue(int n1 = 10, n2 = 100); 3. The default arguments facilitate the function call statement with partial or no arguments.


A function can have multiple signatures if the signatures differ in arity. You can use that to supply default values.

(defn string->integer 
  ([s] (string->integer s 10))
  ([s base] (Integer/parseInt s base)))

Note that assuming false and nil are both considered non-values, (if (nil? base) 10 base) could be shortened to (if base base 10), or further to (or base 10).


You can also destructure rest arguments as a map since Clojure 1.2 [ref]. This lets you name and provide defaults for function arguments:

(defn string->integer [s & {:keys [base] :or {base 10}}]
    (Integer/parseInt s base))

Now you can call

(string->integer "11")
=> 11

or

(string->integer "11" :base 8)
=> 9

You can see this in action here: https://github.com/Raynes/clavatar/blob/master/src/clavatar/core.clj (for example)


This solution is the closer to the spirit of the original solution, but marginally cleaner

(defn string->integer [str & [base]]
  (Integer/parseInt str (or base 10)))

A similar pattern which can be handy uses or combined with let

(defn string->integer [str & [base]]
  (let [base (or base 10)]
    (Integer/parseInt str base)))

While in this case more verbose, it can be useful if you wish to have defaults dependent on other input values. For example, consider the following function:

(defn exemplar [a & [b c]]
  (let [b (or b 5)
        c (or c (* 7 b))]
    ;; or whatever yer actual code might be...
    (println a b c)))

(exemplar 3) => 3 5 35

This approach can easily be extended to work with named arguments (as in M. Gilliar's solution) as well:

(defn exemplar [a & {:keys [b c]}]
  (let [b (or b 5)
        c (or c (* 7 b))]
    (println a b c)))

Or using even more of a fusion:

(defn exemplar [a & {:keys [b c] :or {b 5}}]
  (let [c (or c (* 7 b))]
    (println a b c)))

There is another approach you might want to consider: partial functions. These are arguably a more "functional" and more flexible way to specify default values for functions.

Start by creating (if necessary) a function that has the parameter(s) that you want to provide as default(s) as the leading parameter(s):

(defn string->integer [base str]
  (Integer/parseInt str base))

This is done because Clojure's version of partial lets you provide the "default" values only in the order they appear in the function definition. Once the parameters have been ordered as desired, you can then create a "default" version of the function using the partial function:

(partial string->integer 10)

In order to make this function callable multiple times you could put it in a var using def:

(def decimal (partial string->integer 10))
(decimal "10")
;10

You could also create a "local default" using let:

(let [hex (partial string->integer 16)]
  (* (hex "FF") (hex "AA")))
;43350

The partial function approach has one key advantage over the others: the consumer of the function can still decide what the default value will be rather than the producer of the function without needing to modify the function definition. This is illustrated in the example with hex where I have decided that the default function decimal is not what I want.

Another advantage of this approach is you can assign the default function a different name (decimal, hex, etc) which may be more descriptive and/or a different scope (var, local). The partial function can also be mixed with some of the approaches above if desired:

(defn string->integer 
  ([s] (string->integer s 10))
  ([base s] (Integer/parseInt s base)))

(def hex (partial string->integer 16))

(Note this is slightly different from Brian's answer as the order of the parameters has been reversed for the reasons given at the top of this response)


You might also look into (fnil) https://clojuredocs.org/clojure.core/fnil