Clojure: Calling function from script throws RuntimeException - clojure

i'm newbie to clojure world coming from python background.
i have created a clojure script problem_1.clj:
(defn first_element
[arg]
(println arg))
(first_element [1, 2])
i have installed clojure via sudo apt-get and running script as
>> clojure problem_1.clj
error
Exception in thread "main" java.lang.RuntimeException: Unable to resolve symbol: first_element in this context, compiling:(/home/naveen/Code/repos/clojure-scripts/problems/problem_1.clj:6:1)
Any help would be appreciated, thanks.

You need to add a call to the namespace macro as the very first thing in your file. The namespace should match the name of your file, except that the namespace should use -s, while the file must not contain dashes; use _s instead. The namespace should also be qualified by any enclosing namespaces; although that's not applicable here.
Add (ns problem-1.clj) to the top of your file, and check out its documentation

Related

Error when sharing namespace among files using (in-ns)

I am sharing a namespace among all my ring routes in order to keep each route in its own file, so I have a file routes/core.clj that contains:
(ns test-proxy.routes.core)
;; Some utility functions
Then I start each route handler file like this:
(in-ns 'test-proxy.routes.core)
;; rest of the code
When I start the server, it works perfectly.
But when I make a change in any of the files and reload the page in the browser, I get the following error:
Caused by: java.lang.Exception: Found lib name 'test-proxy.routes.core'
containing period with prefix 'quote'. lib names inside prefix lists
must not contain periods
If I restart the server manually (lein ring server), all works as expected again, but as soon as I make another change in the code base, it fails with the same error. It definitely looks related to the way I'm using namespaces, but what gets me is that it works without a problem when I restart the server.
If I unquote the namespace to (in-ns test-proxy.routes.core) like the error seems to suggest, the server doesn't even start:
Syntax error (ClassNotFoundException) compiling at (diplomat/routes/docs.clj:1:1).
test-proxy.routes.core
in-ns is only meant to be used when at the REPL.
It is fine to divide up your functions any way you want. Just use the fully-qualified name like some.ns.of.mine/my-fn when you reference the function from any other namespace.
Of course, you can always use a namespace alias like:
(ns some.other.ns.of.mine
(:require [some.ns.of.mine :as snom])) ; define namespace alias
....
(snom/my-fn ...) ; invoke the fn
Be sure to also see How to ns

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

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!
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 hyphen 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.

How to debug static initialiser errors in jars generated by Leiningen?

in my Clojure library testlib, i've got a namespace with a :gen-class directive that looks like this:
(ns com.some_long_path.NewClass
(:import (java.util List ArrayList))
(:gen-class
:name com.some_long_path.NewClass
:methods [^{:static true} [getValues [String] java.util.List]]
)
(:require
[testlib.core :refer [var1 var2]]))
(defn getValues [^String]
(java.util.ArrayList. [3 5]))
If i try to import this class inside another namespace in the testlib project (after invoking compile), i can invoke getValues method without errors.
However, if i lein install, include testlib in another project jartest, and then use it in a test namespace below
(ns jartest.core
(:import [com.some_long_path NewClass]))
(NewClass.)
(NewClass/getValues "some string")
invoking NewClass constructor gives an exception
CompilerException java.lang.NoClassDefFoundError: Could not initialize class com.some_long_path.NewClass
and getValues as a consequence gives
CompilerException java.lang.IllegalStateException: Attempting to call unbound fn: #'com.some_long_path.NewClass/getValues
However, if i remove the requires from NewClass namespace definition above, the code works even in another library. So the problem is caused by some missing dependencies, although i've made sure that all dependencies of testlib are also included in jartest, and that testlib.core namespace is AOT-compiled.
Also, i've tried decompiling generated com.some_long_path.NewClass class file, and there is a static initializer block that looks like this:
static
{
Util.loadWithClass("/com/some_long_path/NewClass", NewClass.class);
}
Most probably the above-mentioned error is thrown from within loadWithClass. But how do i find out what exactly is wrong?
Thanks!
UPDATE: I was able to figure out what was wrong in the namespace i was requiring through a binary search for errors (commenting out code until things worked again). It turned out that some files were slurped from resources folder in testlib, but they were not present in jartest project. Changing the code to use clojure.java.io/resource fixed the problem. However, the question still stands - how to find out exactly what was the problem, without resorting to brute force methods?
Here is the obligatory answer- there isnt a better way, without understanding the dependency tree more deeply, which often can only be done by commenting stuff out and seeing what now works. That has been my experience with java classloading from clojure and using gen-class.
Heres hoping this isnt the highest voted answer.

Clojure REPL forgets classpath

I'm a bit of a Clojure newbie and something in the REPL is really confusing me.
I have a project called "misc" and a namespace at "misc/src/counter_window.clj". When I do enter the REPL from the project root folder I want to import counter_window's functions, but I seem to have to go through the following weird tango every time:
user=> (use 'counter-window)
FileNotFoundException Could not locate counter_window__init.class or counter_window.clj on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. clojure.lang.RT.load (RT.java:449)
user=> (use 'misc.counter-window)
CompilerException java.lang.Exception: namespace 'misc.counter-window' not found after loading '/misc/counter_window', compiling:(/tmp/form-init2530455467319465680.clj:1:1)
user=> (use 'counter-window)
nil ;; the import succeeds this third time.
The warning in the FileNotFound exception doesn't seem to apply because the namespace is called counter-window in the counter_window.clj file already.
So why does this happen? Why does the import not work the first time, but then succeed the third time?
I think there is a direct relation between file path and the namespace. A file src/counter_window.clj ought to have the namespace declaration (ns counter-window).
A namespace misc.counter-window should be defined in the file src/misc/counter_window.clj. ie it will have the form (ns misc.counter-window). Note that misc is a folder inside src. Your project could be named anything, I don't think it would affect the namespaces.
Assuming what you wanted was the namespace misc.counter-window and your file is correspondingly at src/misc/counter_window.clj, the following works in the repl
(use '[misc.counter-window])

My clojure function works when defined in the repl but not when loaded from a script

I am using Clojure 1.4.0 on Windows XP (JVM=1.6.0).
My help.clj script contains obscure snippets of Clojure code that I find useful.
In the Clojure repl I can access it from the current directory with (load-file "help.clj").
Trying to be fancy I write (defn clojure-help [] (load-file "help.clj")). Now a simple (clojure-help) loads it.
Then I tried putting the clojure-help function in a repl startup script I use.
But now calling (clojure-help) results in the following Exception:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: clojure-help in this context
What am I missing?
Thanks for posting the code in the comments above! Without the code it's impossible to know what's actually going on. Making one simple change seems to fix the problem:
(defn my-prompt [] (printf "\n[%s]> " (ns-name *ns*)))
(defn p1 [] (clojure.main/repl :prompt my-prompt))
(defn clojure-help [] (load-file "help.clj"))
(p1)
The change was moving the (p1) call to the end of the script. If the call isn't at the end of the script then Clojure drops into the REPL before evaluating the rest of the functions in the script, and thus they are not available in the REPL. Since clojure-help was defined after the (p1) call in your script it was not being evaluated until after exiting the REPL.
If you're not using the repl to load other scripts you could do something like this:
clojure --init replstartup.clj --repl
Where replstartup.clj would contain your closure-help function.
Alternatively you could just create a batch file, named clojure-repl.bat (or some such thing) that looks like this.
#echo off
java -cp %userprofile%\clojure-1.4.0.jar clojure.main --init repl-startup.clj --repl
#echo on