Use `defn` as the normal way to publish named functions, and understand what it adds beyond `def` plus `fn`.
defn is the standard way to define a named function in a namespace.
You can think of it as the idiomatic wrapper around “create a var whose value is a function,” but that summary is only useful if you keep the everyday workflow in view:
defn is how APIs are normally introduceddefn keeps function definitions readabledefn supports docstrings, metadata, and multiple arities in one placeFor Java developers, the main shift is that you are not adding a method to a class. You are binding a function value to a name in a namespace.
1(defn greet
2 "Return a greeting for the supplied user name."
3 [name]
4 (str "Hello, " name "!"))
That one form gives you:
greetAt the REPL:
1(greet "Ada")
2;; => "Hello, Ada!"
The Java comparison is useful only up to a point. greet behaves like a callable API entry point, but it is not attached to an object instance or class hierarchy the way a Java method is.
def And fn Manually?You can:
1(def greet
2 (fn [name]
3 (str "Hello, " name "!")))
That is valid Clojure. But defn is clearer and scales better as soon as you want:
^:privateIn other words, defn is not “magic.” It is the form the language community expects you to use for named functions.
One of the biggest advantages of defn for Java engineers is that overloaded call shapes stay together in one definition:
1(defn describe-order
2 ([order-id]
3 (str "Order " order-id))
4 ([order-id status]
5 (str "Order " order-id " is " status)))
That is similar in purpose to Java method overloads, but the result is still one named function value with several supported arities.
This often reads better than creating multiple helper names when the behavior is clearly the same operation with different input shapes.
defn also supports a rest argument:
1(defn average
2 [& xs]
3 (/ (reduce + xs) (count xs)))
This is conceptually similar to Java varargs, but it stays in the same value-oriented function model as the rest of Clojure.
You can attach metadata directly in the definition:
1(defn ^:private parse-port [s]
2 (Long/parseLong s))
^:private means the var is private to the namespace. That is closer to namespace-level visibility control than to class-member access modifiers.
This is a common pattern for keeping internal helpers out of the public namespace API while still writing ordinary top-level functions.
A common Java instinct is to create a class just to hold related methods.
In Clojure, the better translation is usually:
For example:
1(ns orders.pricing)
2
3(defn line-total [{:keys [qty unit-price]}]
4 (* qty unit-price))
5
6(defn order-total [lines]
7 (reduce + 0M (map line-total lines)))
That is often all you need. No utility class. No object wrapper. Just a namespace of related functions.
defn Is The Wrong Tooldefn is for named functions at the top level of a namespace.
Inside a higher-order function or a one-off call, use fn or the shorthand #() when it stays readable:
1(map (fn [n] (* n 2)) [1 2 3])
If you find yourself trying to use defn inside another function body, stop and ask whether you really want a local helper, an anonymous function, or a top-level reusable definition.