What does the - (minus) symbol in front of function name within Clojure mean?

First, an aside.

Regarding the macros defn vs defn-, the 2nd form 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).


The "main" function in a Clojure Program

In Java, a program is always started by calling the "main" function in a selected class

class Foo
  public static void main( String[] args ) {
    ...
  }
}

and then

> javac Foo.java   ; compile class Foo
> java Foo         ; run at entrypoint Foo.main()

Clojure chooses to name the initial function -main. The hyphen in the function name -main is not really special, except it makes the name unusual so it is less likely to conflict with any other function in your codebase. You can see this in the definition of the function clojure.main/main-opt.

You can see part of the origin of the hypen convention in the docs for gen-class (scroll down to see the part about :prefix). Note that using the hyphen is changeable if using gen-class for java interop.

Using the Clojure Deps & CLI tools, the name -main is assumed as the starting point of the program.


If you are using Leiningen, it is more flexible and allows one to override the -main entrypoint of a program.

In Leiningen projects, an entry like the following indicates where to start when you type lein run:

; assumes a `-main` function exists in the namespace `demo.core` 
:main ^:skip-aot demo.core    

so in a program like this:

(ns demo.core )

(defn foo [& args]
  (newline)
  (println "*** Running in foo program ***")
  (newline))

(defn -main [& args]
  (newline)
  (println "*** Running in main program ***")
  (newline))

we get the normal behavior:

~/expr/demo > lein run

*** Running in main program ***

However, we could invoke the program another way:

> lein run -m demo.core/foo

*** Running in foo program ***

to make the foo function the "entry point". We could also change the :main setting like this:

:main ^:skip-aot demo.core/foo

and get behavior:

~/expr/demo > lein run

*** Running in foo program ***

So, having the initial function of a Clojure program named -main is the default, and is required for most tools. You can override the default if using Leiningen, although this is probably only useful in testing & development.

Please keep in mind that each namespace can have its own -main function, so you can easily change the initial function simply by changing the initial namespace that is invoked.

And finally, the hyphen in -main us unrelated to the hyphen used for pseudo-private functions defined via defn-.


All clojure functions are "static" (digression below). Putting a - as the first character in the name of a function does not have any effect on the behaviour of the function. Using the defn- macro instead of defn makes a function private. -main is ~~by convention~~ the name of the main entry point for a clojure program, if you specify an ns in your project definition as the "main" namespace, the clojure runtime will look for a function named -main and invoke it.

It's not really "by convention" now I think about it. As it's not configurable for the standard tools. It is the one and only name that clojure.main will look for.

https://clojure.org/reference/repl_and_main

All clojure functions are actually an instance of a java object AFunction, with an instance method invoke. So they're not static from a java perspective, but while in clojure land I'd say that they are, as they have no instance that you see. There is also the special case of gen-class, where you define a java class using clojure. In this case you can mark clojure functions as ^:static for the generated java class. This creates a static method in the generated java class that refers to the instance of AFunction.

Tags:

Clojure