I can't get my head around the following. When defining the main function in Clojure (based on code generated by Leinigen), there's an -
symbol in front of the function name main
.
I went to the original documentation on clojure.com and found defn
and defn-
among other things, see https://clojuredocs.org/search?q=defn. I also searched on Google and found a source that said that the -
in front of main indicated that the function was static (http://ben.vandgrift.com/2013/03/13/clojure-hello-world.html).
Does the -
truely mean that the function is static? I couldn't find any other sources that confirmed that. Also I can use both (main)
and (-main)
when calling the main method without any problem.
Given the following code...
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
(defn main
"I don't do a whole lot ... yet."
[& args]
(println "Hello, World!"))
I get the following output...
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
Loading src/clojure_example/core.clj... done
(main)
Hello, World!
=> nil
(-main)
Hello, World!
=> nil
I noticed no difference. Output is the same for both functions. Any help is appreciated!
There may be some confusion here from the different usages of the term "symbol" in Common Lisp and in Clojure. In Common Lisp, a "symbol" is a location in memory, a place where data can be stored. The "value" of a symbol is the data stored at that location in memory. In Clojure, a "symbol" is just a name.
Clojure is a functional language. Functions are first-class and can be passed-to or returned-from other functions. Most Clojure code consists primarily of pure functions (no side effects), so invoking with the same inputs yields the same output.
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).
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-
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With