What is the difference between defn- and defn ^:private in Clojure?

86 Views Asked by At

Both seem to denote a private function, similiar to that found in most OOP languages. Is there a functional difference or is one just syntactic sugar?

I've seen defn ^:private used in the context of the handler of a ring application.

2

There are 2 best solutions below

1
On

Regarding the macro defn-, it is just a shorthand for "private" functions. The long form looks like:

(defn ^:private foo [args] ...)

However, this is just a hint to the user that one shouldn't use these functions. It is easy for testing, etc to work around this weak "private" restriction. Due to the hassle I never use so-called "private" functions (I do sometimes use metadata ^:no-doc and names like foo-impl to indicate a fn is not a part of the public-facing API and should be ignored by library users).

You can view the definition of defn- in the Clojure source code for more details.

0
On

In answer to the original question: there is no difference.

user=> (defn- a1 [b] b)
#'user/a1
user=> (defn ^:private a2 [b] b)
#'user/a2
user=> (meta #'a1)
{:private true, :arglists ([b]), :line 1, :column 1, :file "NO_SOURCE_PATH", :name a1, :ns #object[clojure.lang.Namespace 0xbaf1bb3 "user"]}
user=> (meta #'a2)
{:private true, :arglists ([b]), :line 1, :column 1, :file "NO_SOURCE_PATH", :name a2, :ns #object[clojure.lang.Namespace 0xbaf1bb3 "user"]}
user=> (source defn-)
(defmacro defn-
  "same as defn, yielding non-public def"
  {:added "1.0"}
  [name & decls]
    (list* `defn (with-meta name (assoc (meta name) :private true)) decls))
nil
user=>

As we can see from the source of defn- it is functionally identically to defn with :private true metadata added to the name symbol.