clojure.tools.namespace.repl/refresh not working - clojure

I have this clojure file:
(ns foo.core)
(def bar 1)
And this project.clj:
(defproject foo "version"
:dependencies [[org.clojure/clojure "1.6.0"]]
:main foo.core)
I open a terminal and run lein repl. Then I change the value of bar OUTSIDE the repl.
(def bar 1)
to
(def bar 2)
I change this value on the editor and don't forget to save the file.
Then I run the command in the repl (load-string "(clojure.tools.namespace.repl/refresh)")
I type bar in the repl and still get 1 instead of 2. However if you just run (clojure.tools.namespace.repl/refresh) and then query the value of bar you get 2. Why is this so? Why is the function load-string breaking it?

Apparently, specifying a :main in your project.clj forces the project to use AOT which breaks this.
Source: http://dev.clojure.org/jira/browse/TNS-27

It's not how your invoking refresh, it's when you invoke it.
refresh uses timestamps on files to see when it needs to reload them. This way it only reloads things it needs to. Because you didn't change the file after redefining a var through the repl, it skipped loading that file.
if I start with a file like this:
(ns bla.core)
(def bar 3)
and then call refresh the first time:
bla.core> (load-string"(clojure.tools.namespace.repl/refresh)")
:reloading (bla.core bla.core-test)
:ok
then redefine bar in the repl:
bla.core> (def bar :changed-from-repl)
#'bla.core/bar
and refresh again:
bla.core> (load-string "(clojure.tools.namespace.repl/refresh)")
:reloading ()
:ok
we can see that it didn't reload any namespaces.

Related

lein uberjar results in "Method code too large!"

I have a clojure project that runs fine using lein run, but lein uberjar results in
java.lang.RuntimeException: Method code too large!, compiling:(some_file.clj:1:1)
for the same project. I could trace it down to some_file.clj using a large vector of more than 2000 entries that is defined something like this:
(def x
[[1 :qwre :asdf]
[2 :zxcv :fafa]
...
])
When removing enough entries from that vector, lein uberjar compiles without issues. How can I make uberjar do its job, leaving all entries in the vector?
N.B. When changing x to a constant a la (def ^:const x, lein run will also throw a Method too large! error. And btw, that error occurs in the place where x is used, so just defining the constant is fine, if it is not being used.
There is a 64kb limit on the size of the method in Java. It seems that in your case the method that creates the big vector literal exceeds this limit.
Actually, you can check it by yourself, using a fancy library called clj-java-decompiler. Here's a short example using boot:
(set-env!
:dependencies '[[com.clojure-goes-fast/clj-java-decompiler "0.1.0"]])
(require '[clj-java-decompiler.core :as d])
(d/decompile-form
{}
[[1 :qwre :asdf]
[2 :zxcv :fafa]
[3 :zxcv :fafa]])
;; ==> prints:
;;
;; // Decompiling class: cjd__init
;; import clojure.lang.*;
;;
;; public class cjd__init
;; {
;; public static final AFn const__10;
;;
;; public static void load() {
;; const__10;
;; }
;;
;; public static void __init0() {
;; const__10 = (AFn)Tuple.create((Object)Tuple.create((Object)1L, (Object)RT.keyword((String)null, "qwre"), (Object)RT.keyword((String)null, "asdf")), (Object)Tuple.create((Object)2L, (Object)RT.keyword((String)null, "zxcv"), (Object)RT.keyword((String)null, "fafa")), (Object)Tuple.create((Object)3L, (Object)RT.keyword((String)null, "zxcv"), (Object)RT.keyword((String)null, "fafa")));
;; }
;;
;; static {
;; __init0();
;; Compiler.pushNSandLoader(RT.classForName("cjd__init").getClassLoader());
;; try {
;; load();
;; Var.popThreadBindings();
;; }
;; finally {
;; Var.popThreadBindings();
;; }
;; }
;; }
;;
As you can see, there's a method __init0 that creates the actual Java object for the vector literal. Given enough elements in the vector, size of the method can easily exceed the 64kb limit.
I think, in your case, the easiest solution to this problem will be to put your vector to the file and then slurp+read this file. Something, like this:
file vector.edn:
[[1 :qwre :asdf]
[2 :zxcv :fafa]
...
]
and then in your code:
(def x (clojure.edn/read-string (slurp "vector.edn"))
It turns out ahead-of-time-compilation was the difference between lein run and lein uberjar, as my project.clj contains the (default) line
:profiles {:uberjar {:aot :all}})
when I remove the :aot :all, uberjar finishes without complaining - but also without aot-compiling. So I guess I need to turn off aot, or figure out to limit it to exclude that vector.
But I'd like to be able to have this - albeit huge - vector "literal", and still compile everything. But perhaps factoring that huge vector out into a data file, which is read in at startup is not too bad an idea either. Then I'd be able to leave the :aot :all setting as is.
would it work in your case top wrap the value in a call to delay to cause it to be computed when it's first used?
there are limits on how big a method can be in a java classfile, and each top level form in Clojure (usually) produces a class.
To fix this problem it's useful to arrange to have the constants generated and stored either:
in memory by calculating them at runtime
in the resources directory where they can be read at runtime
don't generate the class file by not compiling it in advance, this generates the data at program start.
if you use a future or make a memoized function to get the data you will compute it at program start and store it in memory rather than the class file.
if you put it in the resources directory it will not be subject to the size limit, and can still be computed at compile time.
if you disable AOT compilation, then the class limit will never be hit becuase it will be computed at load time when the program starts.

Clojure: boot repl in a particular namespace

I have boot-clj installed and want to be able to edit a .clj file in an external editor and separately have a command line REPL running from which I can call the functions that I change in the .clj file. No special reloading commands should be required.
Another thing is I don't want to have to manually type commands to include namespaces - I would like to just run a script that brings me into the namespace, so I can call existing functions right away.
Name of the file:
C:\dev\my-project\src\my_project\utils.clj
Something of what is inside the file:
(ns my-project.utils
(:require
[clojure.string :as s]))
(defn my-range [start end]
(take (- end start) (iterate inc start)))
I would like to go straight into a REPL and go (my-range 0 3) and see if it produces the result I want.
What's the setup for this? What would the script file I need to run look like?
My current understanding is that the answer will look something like this:
(deftask dev-repl
(set-env! …)
(repl))
at the command line
You can achieve this to some degree at the command line, without creating a build.boot file:
In C:\dev\my_project:
boot -r src repl -n my-project.utils
boot -r src: starts boot with src on the "resource paths", which is the set of directories that will be accessible within the JVM.
repl -n my-project.utils starts a REPL, requires your namespace, and enters it.
While the REPL is running, and after you have edited C:\dev\my_project\src\my_project\utils.clj, you can reload it at the REPL like this:
my-project.utils=> (require 'my-project.utils :reload)
nil
minimal build.boot
Alternatively, you could create the file C:\dev\my_project\build.boot with these contents:
(set-env! :resource-paths #{"src"})
(deftask dev
"Run a development REPL"
[]
(repl :init-ns 'my-project.utils))
Then, in C:\dev\my_project:
boot dev
Which will also start a REPL in your namespace, but requires less command-line configuration as we've performed the configuration in build.boot, which boot will automatically evaluate.
Note: from a Clojure REPL, regardless of build tool, you can require any namespace (as long as it's on the JVM's class path) with the require function and enter it with the in-ns function.
build.boot with automatic reloading
Finally, it's possible to combine features of Boot to achieve a development workflow oriented around automatically reloading code.
In C:\dev\my_project\build.boot:
(set-env! :resource-paths #{"src"})
(require '[boot.core :as core]
'[boot.pod :as pod])
(deftask load-ns
"Loads the my-project.utils namespace in a fresh pod."
[]
(let [pods (pod/pod-pool (core/get-env))]
(core/with-pre-wrap [fileset]
(pod/with-eval-in (pods :refresh)
;; We require indirectly here so that errors from my-project.utils have
;; proper line and column information.
(require 'my-project.load-impl))
fileset)))
(deftask dev
"Watches source code and loads my-project/utils every time code changes."
[]
(comp (watch)
(load-ns)))
In C:\dev\my_project\src\my_project\load_impl.clj:
(ns my-project.load-impl)
(require 'my-project.utils)
In C:\dev\my_project\src\my_project\utils.clj:
(ns my-project.utils
(:require
[clojure.string :as s]))
(defn my-range [start end]
(take (- end start) (iterate inc start)))
(println "In the code!")
(println "(my-range 0 10) = " (my-range 10 20))
Back at the command prompt, type boot dev. You should see some println output, and every time you edit and save the file you should see it again, reflecting any changes you made.

Why can't Leiningen always use my :gen-class properly?

Let's say I create a new Leiningen project (lein new app example) and add some code in example/src/example/core.clj that makes use of :gen-class:
(ns example.core
(:gen-class :extends javafx.application.Application))
(defn -start [this stage]
(.show stage))
(defn -main [& args]
(javafx.application.Application/launch example.core args))
If I then create a JAR (lein uberjar) and run it, everything works fine. However, if I instead try to run my app directly (lein run), I get a ClassNotFoundException. In addition, if I open a REPL (lein repl), I first get the same error as before, but after running this code:
(compile 'example.core)
the error no longer appears in lein run or lein repl.
Could someone please explain to me what exactly is going on here, and how I can run my app directly without needing to manually compile my code from a REPL?
Edit: After fooling around a bit more, I found that the solution to this problem is to add
:aot [example.core]
to project.clj. (Thanks #Mars!) I'm still confused, though, because I had previously tried simply removing ^:skip-aot, which (according to the docs) should work:
This will be AOT compiled by default; to disable this, attach
^:skip-aot metadata to the namespace symbol.
But it doesn't. Why?
Another edit (if I should split any of this into a separate question, let me know and I'll do so): I've been playing with hyphens (lein new app my-example), and weird stuff has been happening. This doesn't work:
(ns my-example.core
(:gen-class :extends javafx.application.Application))
;; ...
(defn -main [& args]
(javafx.application.Application/launch my-example.core args))
But this does:
(ns my-example.core
(:gen-class
:name my-example.Core
:extends javafx.application.Application))
;; ...
(defn -main [& args]
(javafx.application.Application/launch my-example.Core args))
So my class name can either start with a lowercase letter (example.core) or contain a hyphen (my-example.Core), but not both? I really don't get it.
And finally, lein uberjar fails on that final example (with the explicit :name), because
Warning: The Main-Class specified does not exist within the jar. It may not be executable as expected. A gen-class directive may be missing in the namespace which contains the main method.
As far as I can tell, the only way to fix that is to split the Application subclass into a separate namespace. Is there another way?
Agreed with #Mars, the problem is that lein run does not AOT the example.core namespace. The default Leiningen template made the example.core non AOT:
(defproject example "0.1.0-SNAPSHOT"
...
:main ^:skip-aot example.core
...)
My best guess is that you could define your app using defrecord and use that as a class instead of the namespace.

Clojure JavaFX -- Toolkit Not Initialized error

JavaFX 8, Java 1.8.0_31, Windows 7 x64
I have a minimal JavaFX program in Clojure. The (ns...) clause is able to import the required Java packages fine except the classes in javafx.scene.control, such as Button and TextField, etc.
I have to put the import for these after initializing the toolkit. Why can't I import these classes before the toolkit is initialized? I'm not actually creating any objects yet... so I'm guessing JFX is somehow doing something in the background while these classes are imported, requiring the initialization first. Below is my complete lein project (minimized from the actual application where I saw this problem, and without all the nice macros that clean up the JFX syntax):
File project.clj:
(defproject jfx-so "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.6.0"]]
:main jfx-so.core)
File src/jfx_so/core.clj:
(ns jfx-so.core
(:import [javafx.scene Scene]
[javafx.scene.layout BorderPane]
[javafx.stage Stage]))
(defonce force-toolkit-init (javafx.embed.swing.JFXPanel.))
;; For some reason the following must be imported after initting the toolkit
(import [javafx.scene.control Button])
(defn -main [& args]
(javafx.application.Platform/runLater
#(doto (Stage.)
(.setScene (Scene. (BorderPane. (Button. "Hello"))))
(.show))))
Thanks! :)
I haven't had a problem with this. Perhaps it has to do with your defonce?
I do my imports first. But I do make sure to init the FX-envoronment before instanciating any FX-classes. So after your -main-method I would put:
(defn -main [& args]
;;body here
)
;; initialze the environement
(javafx.embed.swing.JFXPanel.)
;; ensure I can keep reloading and running without restarting JVM every time
(javafx.application.Platform/setImplicitExit false)
;; then
(-main)
Hope this helps.

Clojure: Lein run unable to resolve symbol

I just started on my first clojure project using lein, the code here:
(ns fileops.core
(:use
[clojure.core :only (slurp)]
[clojure-csv.core :only (parse-csv)]
[fileops.core]))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(read-file "sample.csv"))
(defn read-file
"open and read the csv file"
[fname]
(with-open [file (clojure.java.io/reader fname)]
(parse-csv (slurp fname))))
I tried to run this using "lein run" but I keep getting this error:
Caused by: java.lang.RuntimeException: Unable to resolve symbol: read-file in this context
at clojure.lang.Util.runtimeException(Util.java:219)
at clojure.lang.Compiler.resolveIn(Compiler.java:6874)
at clojure.lang.Compiler.resolve(Compiler.java:6818)
at clojure.lang.Compiler.analyzeSymbol(Compiler.java:6779)
at clojure.lang.Compiler.analyze(Compiler.java:6343)
... 52 more
What am I doing wrong?
You have used only slurp from clojure core, meaning that every other core function is now unavailable to you :) Try changing your ns to use :require instead of :use, as this is more idiomatic.
One thing to note is that order does matter in clojure, so if you don't declare a function at the top of your file, as in C and some other languages, the earlier functions will not be able to make reference to them. This is what was causing your error before and is why I like to define my -main function at the bottom. It's a matter of style.
Another thing is that your -main function is taking variable args right now and not using them. In Clojure it is idiomatic to use _ to refer to a parameter that doesn't get used. You could use & _ to avoid error messages, for when the user passes in unnecessary args, but I would just have the -main function parameterless from the start. This is because nothing needs to be provided to main when you run the program, and errors do make debugging easier. It is good to know what is getting used and where. The sample.csv file is already provided and is having read-file called on it, so the program should run if your read-file function is correct and the sample.csv file is in the proper location.
Regarding your -main function, it would be nice to put a little test in there to see if it executes properly when you run it, so I changed it to print out the contents of the csv file onto your console. This way of printing from a file is efficient and worth studying in its own right.
Finally, Make sure you include clojure-csv.core in your project.clj file.
core.clj:
(ns fileops.core
(:require
[clojure-csv.core :refer [parse-csv]]))
(defn read-file
"open and read the csv file"
[fname]
(with-open [file (clojure.java.io/reader fname)]
(parse-csv (slurp fname))))
(defn -main []
(println (clojure.string/join "\n" (read-file "resources/test.csv"))))
project.clj:
...
:dependencies [[org.clojure/clojure "1.5.1"]
[clojure-csv/clojure-csv "2.0.1"]
...]
:main fileops.core
You need to declare fileops.core as :main, as shown above. This tells Leiningen what function to execute when you enter lein run. Very important and tricky stuff.
So now make sure you are in the root of your project directory and at the terminal, run the following:
lein clean
lein deps
lein run
Good luck!
Further reading:
8th light blog on name-spaces
flying machine studios explanation of lein run
read-file should be before main in your source OR you should put before -main a declare cause like that:
(declare read-file)