Fork me on GitHub
#leiningen
<
2019-02-20
>
anthony-galea15:02:28

Just came across an issue with the latest lein release v2.9.0:

─$ git clone 

# with lein 2.9.0
─$ lein do clean, compile
Compiling quil.applet
java.lang.ClassNotFoundException: quil.helpers.AppletListener, compiling:(quil/applet.clj:256:22)
Exception in thread "main" java.lang.ClassNotFoundException: quil.helpers.AppletListener, compiling:(quil/applet.clj:256:22)
...
Caused by: java.lang.ClassNotFoundException: quil.helpers.AppletListener

# after downgrading to lein 2.8.3:
─$ lein do clean, compile
Compiling quil.helpers.applet-listener
Compiling quil.applet

─$ java -version
java version "1.8.0_202"
Has anyone seen anything similar?

Noah Bogart15:02:03

Is there a race condition in the compilation?

Alex Miller (Clojure team)16:02:23

are you using :aot :all ?

Alex Miller (Clojure team)16:02:25

looks like, no (there was a possible change in compilation order with that in lein 2.9.0)

Alex Miller (Clojure team)16:02:36

oh wait, you are seeing a difference in order there

Alex Miller (Clojure team)16:02:57

project.clj has :aot [quil.helpers.applet-listener quil.applet] - but you are seeing quil.applet compiled first

Alex Miller (Clojure team)16:02:42

that sort was supposed to only occur for :aot :all based on what I was told. if not, then I'd say that's a regression and you should file a bug

mikerod16:02:55

Yeah, looks like it sorts all forms of :aot

mikerod16:02:02

from that commit above.

mikerod16:02:15

However, isn’t it not really a good impl in quil.applet to not require the namespace that the class is defined in?

mikerod16:02:41

Not saying lein should resort your list, just thinking, that’d break with :aot :all if you chose to go that route instead later

mikerod16:02:39

I mean, quil.applet refers to the class quil.helpers.AppletListener, without adding a :require for quil.helpers.applet-listener I tend to consider that a faulty ns

Alex Miller (Clojure team)16:02:49

it's loading a gen-class though?

Alex Miller (Clojure team)16:02:56

if I'm reading it right, AppletListener is a genclass. aot is being used to compile it. applet is just using it purely as a java class.

Alex Miller (Clojure team)16:02:25

that all seems sane to me

mikerod16:02:32

@alexmiller It’s loading a gen-class’ed class

mikerod16:02:48

but if you did AOT :all and is “started” with the ns quil.applet, it’d fail I think

mikerod16:02:05

due to the missing :require so it wouldn’t know to first compile that ns

mikerod16:02:36

Well, I did learn now that lein :aot :all calls repeated compile on each ns. Not a big fan of that due to duplicated loading concerns. Yikes

mikerod16:02:50

I wish it would just take a “single entry point” ns that transitively requires all else - so only one compile goes

Alex Miller (Clojure team)16:02:52

well, yes. that's why you sometimes need to order your aot calls

mikerod16:02:19

but seems like you wouldn’t have the ordering problem if you have a single top-level ns that causes the transitive (one time load) of everything it depends on

mikerod16:02:38

but thanks for the reddit pointer. all stuff I was unaware of and good to know about now.

mikerod16:02:16

I still think if I use a gen-class class from another ns, I always make taht explicit with a (:require [quil.helpers.applet-listener]) <- the ns that defines the gen-class

Alex Miller (Clojure team)16:02:15

I don't think there is any reason to in this case

anthony-galea16:02:38

@mikerod fyi just tried :aot :all with lein 2.8.3. Without the require I get a ClassNotFoundException for AppletListener and with the require I don’t as you expected. Order of compilation:

...
Compiling quil.applet
...
Compiling quil.helpers.applet-listener
...

mikerod17:02:30

@anthony-galea @alexmiller Yeah, the general rule I’m getting at is that if a ns requires another ns to be pre-loaded - for any reason, including side effects like gen-class - then it should explicitly ensure that other ns is loaded - typically via adding it to :require (or something that loads appropriately). So this quil ns, assumes the gen-class class exists, but never ensures the ns that creates it is loaded. That violates my “general rule” here. I think it’s a brittle pattern when you don’t make your direct dependencies explicitly called out. ie. I’d expect to be able to do (compile 'quil.applet) and have success with no prior compile calls to ns’s it depends on. All that aside though, I didn’t realize that (1) :aot :all in lein calls compile multiple times for possibly inter-related ns’s and (2) now there is this sorting happening both for all and what looks like the explicit ns vector way.

Alex Miller (Clojure team)17:02:06

That’s how aot works in all tools

😱 5