Fork me on GitHub

I just ran into the fact that compile doesn't compile anything that's already loaded. I can't seem to see anywhere that specifies this behaviour. Is this a long standing bug with no good / intended fix? Is this documented somewhere and I can add that place to my check list when understanding things.

Alex Miller (Clojure team)17:09:22

compilation happens as a side effect of load so that makes conceptually makes sense to me

Alex Miller (Clojure team)17:09:22

I wouldn’t say it’s a bug and it seems like it it worked otherwise, compilation would result in a lot of recompilation when compiling many namespaces


It's a problem because the root namespace doesn't look for the .clj too, so it actually fails when run.


In my case I did an AOT of user (root ns), edge.system was already loaded though, so didn't AOT. When I tried to use user as a main from that directory later, it failed because it couldn't find edge/system$new_system.class


Even though edge/system.clj was present. Message didn't indicate that it tried both.


To clarify, you AOTed 'user, which was already loaded by the time you asked for 'user to get compiled

👍 4

I'm very bad at articulating things like this, I apologize.

Alex Miller (Clojure team)17:09:34

given that user is special-cased into the runtime, this is a particularly weird case

Alex Miller (Clojure team)17:09:45

so I’d suggest not doing that :)


I agree. I think it would happen in other cases too. I'm certain I saw it a while ago in another project not using user.


It actually doesn't matter which ns you AOTed - any thing required by user would be affected

Alex Miller (Clojure team)17:09:58

exactly - user is designed NOT to be AOT’ed (as the runtime explicitly loads user.clj)


But if I have a user.clj in my classpath that requires edge.main, that would cause this bug too.


Or if I run compile from the repl.

Alex Miller (Clojure team)18:09:26

so, don’t load stuff in user.clj?


That's a fine answer, if it's the intended behaviour. It does cause minor issues trying to write a build system that doesn't have to spin up a whole extra jvm/pod just for aot.


There are workarounds though, so nothing pressing. But if it's something that could be enhanced, then I'm happy to open a jira, or vote for one. If there's a reason that it should stay this way then that's knowledge worth having too.

Alex Miller (Clojure team)18:09:33

I said the reasons above

Alex Miller (Clojure team)18:09:55

if compile recompiled loaded stuff then every compile would recompile everything


Why is that a problem? I guess that's what I'm missing?

Alex Miller (Clojure team)19:09:07

Because most people don’t their compile time to be n!

Alex Miller (Clojure team)19:09:07

I guess more n^2 or something


I suppose the caching seems wrong to me. I would expect caching to be based on the class file, not what is loaded in memory, and possibly not on disk.


What is the expectation for use here? Where this form of caching is advantageous.

Alex Miller (Clojure team)19:09:32

it’s just leveraging the existing load system which transitively loads namespaces. if you encounter a new (unloaded) namespace, compile it

Alex Miller (Clojure team)19:09:31

you’re N steps down the decision chain here, asking “why X”. it’s difficult to walk that chain backwards, recovering all the design decisions from 10 years ago.


Leveraging the load system I understand. It's a fairly convenient way to implement this. Sorry, I think I have misunderstood. I thought you were implying that the expected common case for compile involved a scenario where skipping loaded namespaces was useful. I was trying to figure out what the expected workflow is exactly. I understand that performance is a feature, but I wouldn't expect it at this kind of detriment to compile. With limited experience with the larger picture for this feature, this limitation seems arbitrary, verging on accident of history. Which is okay too, I am not interested in the why of how it happened so much as why it should stay the way it is.


I don't have experience in dealing with the detailed behavior of compile here, so out of my depth, but in general a reason for things to stay the way they are is to avoid creating possible bugs in build and/or deployment flows that people are using today.

Alex Miller (Clojure team)21:09:37

“I thought you were implying that the expected common case for compile involved a scenario where skipping loaded namespaces was useful.” - yes I was saying that

Alex Miller (Clojure team)21:09:11

if you are in a project and you want to compile everything in the project, you need to invoke compile for every namespace in the project

Alex Miller (Clojure team)21:09:50

you don’t want every one of those calls to recompile every namespace

Alex Miller (Clojure team)21:09:03

you want to compile every namespace once

Alex Miller (Clojure team)21:09:26

by compiling on load and leveraging the set of loaded namespaces as a tracking mechanism, you achieve that