Share your thoughts in the 2020 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Clojure by

So I caught myself doing some errors when using multi-arity. For example

(defn foo
  ([]
   (foo "blah"))
  ([bar]
   (println bar)))

Then I want to make another version

(defn foo2
  ([]
   (foo "blah"))
  ([bar]
   (println (str "your foo is " bar)))

Now in foo2 I forgot the call to foo (instead of chaning it to foo2). Wouldn't make things much easier calling something like (self ...) in the same concept that you call (recur ...) for recursion? Or such a thing like this exists and I've missed it?

PS
First post here, happily learning clojure :)

2 Answers

+2 votes
by
selected by
 
Best answer

As Alex pointed out, self doesn't exist, but since Clojure is a Lisp you could trivially add this support. I'm not recommending you do this, but it's fun.

We'll want symbol macros, which work like macros but are, well, symbols (in this case we'll use symbol-macrolet from the org.clojure/clojure.tools.macro library).

Try this!

From the command line:

clj -Sdeps '{:deps {org.clojure/tools.macro {:mvn/version "0.1.2"}}}'

Once you have a repl, we'll pull in the tools.macro library:

(require '[clojure.tools.macro :refer [symbol-macrolet]])

Then, we'll define a new macro, defns, which will allow you to refer to the function name using self:

(defmacro defns
 [name & args]
 `(symbol-macrolet [~'self ~name]
    (defn ~name
      ~@args)))

Usage:

Define a function using defns:

(defns foo
 ([] (self 2))
 ([n] (* 2 n)))

test it:

user=> (foo)
4
user=> (foo 5)
10

Be careful with macros though– they're a lot of fun and easy to abuse. ;)

by
Thanks for the provided example!
I was guessing that it could be done with a macro (was even thinking the `defns` naming :) ) but haven't touched this aspect yet.

My current solution was using a `(let [self function-name] ..body..)` once in the top, to avoid writing long function names :)
+1 vote
by

Welcome! No, that doesn't exist, you need to call foo2 there.

...