Fork me on GitHub
Jim Newton15:06:51

Hi everyone, is there a way to tell lein which order to load the files in? especially in the case that the load order cannot be determined by name space requirements?

Jim Newton16:06:26

The only way I can think of doing it is to create empty name spaces, one per file which needs to be loaded. And then :require those name spaces in the order which I know they need to be loaded. This seems to work, but sounds like a hack.


@jimka.issy what do you mean by “load files in”?


as in compile them?


like via :aot option?

Jim Newton18:06:34

@mikerod, if you have several files in the directory, it seems the project.clj file indicates in the defproject which is the first file to load via the :main keyword. And thereafter if any file defines a ns which requires other packages to be loaded, they seem to be loaded by assuming the name of the file matches the ns name.

Jim Newton18:06:44

what about other files which don't match the ns name?

Jim Newton18:06:58

how am I supposed to force them to be loaded?

Jim Newton18:06:36

as per the compilation, as I understand it load semantics and are the same whether loading from source and compiling on the fly, or loading from pre-compiled files. right?

Jim Newton18:06:31

an example would be a file which does not begin with (ns ...) but rather begins with (in-ns ...)


As in, the file beginning with (in-ns ...) is code that belongs in a namespace whose (ns ..) form is in another file?


If yes, then I have seen such files loaded from the file containing the (ns ...) form in clojure.core's namespace, like this:

(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")

Jim Newton19:06:20

what's the path name relative to?

Jim Newton19:06:16

re your question above. yes. several files which contribute to the same ns.

Jim Newton19:06:57

The way I've figured out how to do it is just define a bunch of empty name spaces, one per file, And the top of the files look like the following

(ns clojure-rte.type-extend
  "This is an empty namespace to fool lein to load this file as part of
  the clojure-rte.core ns.")

(in-ns 'clojure-rte.core)

Jim Newton19:06:18

I wonder whether it is better to call load directly. My guess is that calling load directly will confuse lein when trying to print error messages if a problem happens at load time. Just my but feel though.


If you want to avoid the question, you can simply put all code that you want to belong in one namespace in one file, with a name corresponding to the namespace name. The upper limit on the size of one is quite large (not sure what exactly determines it).


Using load like used in the clojure.core namespace you can split the contents of a single namespace across multiple files.


The load calls in any namespace should execute whenever ns is require'd, or loaded in any way, I believe.


I would expect it would be confusing to many readers of code to have an ns form at the beginning of a file, which corresponded to the file name, but then soon afterwards have (in-ns ..)` with a different namespace name, and none of the code was actually in the namespace named in the ns form. Obviously Clojure allows you to do this -- just saying it would look odd to me.

Jim Newton15:06:13

The problem is that lein assumes ns name is derivable from file name. This is an unfortunate assumption which was not intended by clojure's design, otherwise in-ns would not exist. In my opinion this is a bug in lein, in that it is requiring the user to provide redunant information.

Jim Newton16:06:07

bug is a strong work. I understand the heritage comes from java, so we're not starting from a perfect world by any means.


I don't think there is actually a requirement in Leiningen for every source file to start with an ns form with a name that corresponds to the file name. Clojure require given a namespace name will always look for it in a file with a corresponding file name, but I doubt Leiningen imposes any more requirements than that.


Here is a tiny demo Leiningen project demonstrating that one can have files that contain no ns form at the beginning, that can be loaded via a call to load from a different source file in the same project:


I have heard Stuart Halloway make a comment noting that while require has this namespace<->filename correspondence built into it, you can concatenate the contents of most (all?) multi-file Clojure projects in a valid order where things are defined before they are used, and just concatenate those all into one big file, or copy and paste that all into a REPL session, and the issue of file names, and even of files in the file system, never arises, and things can work that way.


Most people don't create Clojure code bases that way, of course.


I suspect that the creation of in-ns was motivated more by live REPL development, and the desire to switch from one namespace to another in a live REPL session, more than anything else.

Jim Newton18:06:59

Can someone help me find the documentation for defproject ?

Jim Newton18:06:18

i.e., what are all the possible options and their meanings?


One source is a huge sample project.clj file included with Leiningen that has many comments. Not necessarily full documentation, but at least mentions most possible things:

✔️ 4