Fork me on GitHub

I'm finally getting productive with clojure, but now I'm finding out that sizable (read: useful) projects take forever to load a repl (I use cider/emacs)... we're talking a couple minutes per bounce... what am I doing wrong?

Alex Miller (Clojure team)03:04:25

if you're using user.clj and a very recent JDK version, you might have stumbled into a Java performance regression

Alex Miller (Clojure team)03:04:52

jdk 1.8u202+, 11.0.2, 12, etc

Alex Miller (Clojure team)03:04:37

you could try downgrading your java version or upgrading Clojure to 1.10.1-beta2 to see if that helps


@macrobartfast As a sanity check, I just timed my REPL startup time -- via clj with a profile that contains every single dependency our 80,000+ line Clojure project uses, which also starts a Socket REPL and starts up Cognitect's REBL tool. A cold start to a live REPL with REBL open takes just under 12 seconds on my Mac.


ok, so it's something wrong with my setup, for sure.


and that's crazy fast, btw.


Per Alex, it could be the JVM regression if you're on either of those versions...


I think 12 seconds is slow 🙂


java version "1.8.0_92" Java(TM) SE Runtime Environment (build 1.8.0_92-b14) Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)


(without REBL and the Socket REPL, starting a plain REPL takes about 8 seconds for comparison)


OK, so on that version of Java/JVM it's unlikely to be the regression Alex mentioned.


it's very likely something wrong with my code, right?


I mean, that can affect things, I'm guessing.


Maybe ask in #cider and/or #emacs and see if they can suggest ways to optimize startup?


sounds like a plan.


I could generate a new project and see how long that takes.


Also, I'm starting a REPL into the user namespace which means it doesn't need to load my main namespace.


lein repl on a project generated with

lein new app test
took about 11 seconds.


(! 780)-> lein new app timing
Generating a project called timing based on the 'app' template.
(! 781)-> cd timing
(! 782)-> time lein repl < /dev/null
nREPL server started on port 57337 on host ...
timing.core=> Bye for now!

real	0m7.290s
user	0m5.564s
sys	0m0.490s
(! 783)-> time lein repl < /dev/null
nREPL server started on port 57351 on host ...
timing.core=> Bye for now!

real	0m6.634s
user	0m5.467s
sys	0m0.486s
(! 784)-> 
6.6 vs your 11.


ok, both are close enough for me 😉


Leiningen adds a lot of overhead, compared to the CLI/`deps.edn` stuff, just FYI:

(! 787)-> clj -A:new app timing.core
Generating a project called timing.core based on the 'app' template.
(! 788)-> cd timing.core/
(! 789)-> time clj < /dev/null
Clojure 1.10.1-beta2

real	0m4.462s
user	0m11.724s
sys	0m0.563s
(! 790)-> time clj < /dev/null
Clojure 1.10.1-beta2

real	0m1.385s
user	0m2.742s
sys	0m0.194s
(! 791)-> 
6.6 goes down to 1.4 🙂


I'll also look at the CLI/deps.edn stuff, which I know nothing about.


We love it. We switched from Boot to CLI last year (after switching from Leiningen to Boot just over three years ago).


I usually just lein repl at the root of the project... how would I specify a namespace?


It depends what's in your project.clj -- when the REPL starts, is it in user or some project-specific ns?


so it's not that.


it is a big luminus rest service type thing, so it's a larger project.


I've also found (and it was a long time ago) that luminus-based projects have quite a long startup time; and it was a very simple service actually. It's perhaps because of many depedencies it introduces...


well, you've given me a few things to look at in the morning.


probably is something to do with cider/emacs and all that, per what you were saying.


thanks for all the help!

Alex Miller (Clojure team)04:04:08

the luminus setup usually has a user.clj file and loads (and compiles) a large set of your project and dependent files on startup. I would look more carefully and see if you're doing something at the top level somewhere in addition to that too.

Alex Miller (Clojure team)04:04:20

like def'ing something that loads from a database, et c

Alex Miller (Clojure team)04:04:41

you can often use a delay to avoid doing that too eagerly


Any way to spec something as a list or a cons? Is there a pred for that? Basically, I want a pred for clojure code


To spec a macro


Hum, looks like seq? could do

Alex Miller (Clojure team)04:04:35

generally, I find it's best to spec inputs to macros using the regex ops


I have (s/+ seq?)


Where it takes one or more s-exprs


Would you do something different?

Alex Miller (Clojure team)11:04:46

I would prob do (s/+ any?)

Alex Miller (Clojure team)11:04:28

There are a lot of valid Clojure forms that are not seqs


Thanks, I'll have a look at it again. I guess I'm not sure why I ever tried to restrict it in the first place.

Alex Miller (Clojure team)16:04:23

usually not worth it in macro args

Ivan Koz07:04:45

whats the difference between fn and fn*? Can't find a declaration of latter.


fn is technically a "special form" but it is implemented as a macro that calls fn* which is part of the compiler


Like let is a special form too, but it is also implemented as a macro that uses let*...


I am writing some cljc code and realizing that there must be something about JVM-clojure and namespaced type hints that I don’t understand. If I have a type/record, I seem to be able to use its name as a type hint within its own namespace, but not from another namespace? example:


@mhuebert in jvm clojure MyType will be a generated class, you'd need to import it


@mail462 ah, ok, thanks!


you don't necessarily need to import it, you simply need to refer to it as a class rather than as a Var


n/T is not valid syntax for classes in clojure/jvm


it needs to be n.T (namespace aliases are not valid either,`n` must be fully qualified)


it's unfortunate that clojure script diverged for deftypes


so I guess it needs to be ^hints.my_type.MyType - also munging the - to _


yes -- import would just allow shorter naming, MyType (closer to t/MyType from the example)


so (:import hints.my_type.MyType)


and then I suppose I would refer MyType in the cljs version, so that a plain ^MyType annotation works for both

Ivan Koz15:04:15

does subvec allows for garbage collecting of unused nodes say if we want [1 2 3] -> [2 3] what is my options aside from vec -> seq -> vec

Alex Miller (Clojure team)15:04:05

ideally, don't use a vector in the first place if you need to remove elements any place but the end

Alex Miller (Clojure team)15:04:45

subvec will keep the original vector in memory so will not be gc'ed

Ivan Koz15:04:06

alex, thanks for everything you are doing for us btw, i'm a fan 😃

💯 32
🙏 12
fan 8

is there a way to set use-context-classloader false before clojure starts?

Alex Miller (Clojure team)16:04:48

how are you starting clojure?


How do i create a var in a another namespace? I know that it is not common, but I'm doing a DSL that "compiles" to #clara, and clara use vars in namespaces...


Hey all, we’ve written a post on the Amperity Eng blog on Greenlight (our Clojure integration testing library).

🚦 12

Oh wow that is seriously cool. I’ve seen the project before but never got the value proposition. Are you aware of ? I’m using kaocha for running other tests.


Silly question, can all the clojure.test compatible assertions be used?


Hey @U7PBP4UVA thanks we have seen that. I think the answer to your question is yes they should work. Feel free to file an issue if you find out this isn’t the case


@U5JFWFE2V Looks good! Am I right to observe that the step idea has some overlap with ideas from Cucumber? Or is that just accidental?


I certainly don’t know anything about it, but can ask internally from contributers


@alexmiller java -jar [uberjar] args


this code runs when i 'lein run' it but some jars fail their static initializers that try to classload XML expecting to get the system classloader (AFAIK)

Alex Miller (Clojure team)17:04:39

user.clj is loaded pretty early in the RT - you could try adding one that sets *use-context-classloader*