On Dec 10, 2008, at 8:51 AM, Stuart Halloway wrote:

Thanks for the info. Is this limitation of user.clj arbitrary, or
motivated by some concern that the average Clojure user should know
about?  Is the a reason not to load the bindings first? Does user.clj
(in current form) do more harm than good?


I think it comes down to separating "Clojure the library of capabilities" from "Clojure the platform for running Clojure repls and programs".

Initializing the library

By default the Clojure library provides its many capabilities and a user namespace that's empty and refers to clojure.core. The "user.clj" hook is provided to configure the Clojure library such that the "user" namespace is not empty. It may provide arbitrary capabilities beyond what's provided by Clojure out of the box including loading other namespaces. user.clj is loaded at static initialization time, it runs to completion and exits. When static init time is over, the augmented Clojure library including customizations from user.clj is loaded and ready, but nothing is running.

Defining the Platform

The Clojure platform is the Clojure library plus an entry point function. The Clojure distribution provides a few entry point functions, but a user of the Clojure library is also free to write their own. I think it makes sense for the Clojure distribution to provide only one entry point function out of the box. That's what clojure.main/-main is intended to be *see note below*. Clojure.main/- main can provide a repl, or run a program, or just do a calculation and exit. I think it should replace Repl.java and Script.java. Clojure.main/-main does push bindings for several vars to make them settable and it does it the same way whether it's providing a repl, a script, or an eval: see clojure.main/with-bindings .

Initializing the Platform

I think Clojure should provide one or more hooks (in the form of files that are loaded automatically if present) for initializing the one platform it provides. If there's only one hook, I think <classpath>/ init.clj would be a good choice. It would be loaded every time Clojure.main/-main runs and it would do so after thread bindings have been pushed so it could "set!" any of the variables covered by clojure.main/with-bindings.

This hook would *not* be loaded automatically if the user provides their own entry point function that uses the Clojure library. This is in contrast to user.clj which will *always* be loaded if present.

Beyond <classpath>/init.clj which runs for repl, script, and eval sessions, a <classpath>/repl-init.clj hook would also be useful. In it, one could customize how repls behave independently from how scripts behave. For example, I would set *print-length* in repl- init.clj, but not init.clj.

Summary

- user.clj is the way it is for a good reason: it must run to completion to provide an initialized Clojure library augmented with custom capabilities. Since it doesn't wrap a runtime session, it shouldn't be the way enable setting of vars and doesn't need to support setting of vars.

- I think init.clj and repl-init.clj would be good additions to what we have now. I'll be happy to write the code if it's welcome.

--Steve

*note* on 7 December, on this mailing list, "User Jon" suggested that Clojure have a tiny main function written in Java whose role it is to invoke clojure.main/-main. This would relax the current requirement that clojure.jar contain compiled Clojure code. I agree with that suggestion and plan to provide a patch that implements that idea if it's welcome.

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to