-
Notifications
You must be signed in to change notification settings - Fork 0
Why not just compile it?
Reasonable question is why don't I just use lein to compile clojure sources into jars and deploy that as any other library. The short answer is: because it would be unpredictable mess. The long answer is bellow.
Essentially both — it's language that compiles to bytecode and adds it's own runtime on top of the JVM.
Clojure code runs on top of the JVM, can be compiled into jars, however is more than a simple library. By default it is compiled on-demand and additionally it can be compiled to .class files offline/Ahead Of Time (AOT), however the bytecode produced in both cases is equal. It is true LISPy dynamic language and this requires some sort of runtime.
In Clojure's case the runtime is implemented as set of Java classes that heavily rely on static variables and static initializers. Major part of this runtime state is the registry of the loaded namespaces (think Java packages) and due to the design decision to use static structures, it's inherently shared. Major side effect is that all namespaces ever loaded would be visible to each other and thus no module boundaries can be enforced within one runtime.
It's important to understand that Clojure resolves namespaces by dereferencing global vars (and symbols), so once a namespace is loaded, regardless via which clossloader, it's globally accessible.
Further reading on that topic: Clojure Compilation: Parenthetical Prose to Bewildering Bytecode
One more fact that pulls towards "runtime" situation is Clojure's use of own classloaders (and hierarchy) that are extremely fine-grained. I did not dig into detail but it looks as if each and every form get's own classloader with parent the classloader of the parent form.