On Apr 17, 2009, at 5:21 PM, Tom Faulhaber wrote: > I'd also like to see a little more focus on the perl/python/ruby > equivalence from a newbie perspective. That is, more clarity around > startup, script execution (including having an equivalent to python's > "if __name__ == '__main__':" construct), class path management, etc. > I know that this is one area where being in the JVM ecosystem makes > our life worse rather than better, but approaching Clojure is still a > bit daunting compared to these other languages.
I have a proposal for a standard way to make a namespace "executable" and to invoke it as a program/script. The basic idea is to mark each namespace intended to be run as "program" such that its entry point can be found and to provide support for calling that entry point easily. An outline: - add a key to the "ns" form to specify, as a symbol, the name of a function to be called when the namespace is "invoked" as a script. - I propose ":run" (with no default so no namespace is ever accidentally executable.) - If provided, the :run value in the ns form is stored as the :run value in the namespace's metadata. - The run function should - accept/expect Strings as arguments - it may accept any number of Strings using normal Clojure arity rules. - return an Integer - zero indicates success - non-zero indicates (some kind of) failure - error codes should be chosen and documented by the namespace author - add a function to clojure.core to run an executable namespace: - (run ns-name arg*) - requires the namespace - retrieves the namespace's :run value and resolves it to a var in the namespace. - calls that function via: (apply the-run-func args) - returns the integer that the-run-func returns - add support to clojure-main to handle a namespace name in "script position" by: - calling "run" on it, passing *command-line-args* in for the args. - returning the status value to the OS via Java's System/exit facility This would be a change away from the current handling of scripts which simply loads them, expecting them to do their operation at load time. It also requires the resource (file) that contains the script be in classpath. (Though that's easy to accomplish by adding "<path-to-the- script>" to classpath.) With this method, we have a new standard way to invoke a script, and the scripts we load this way are "clean" in the sense that they don't run arbitrary code while loading. (They can, of course, run arbitrary code during macro expansion but it's still a good idea not to have bits of executable code laying around being loaded when the namespace's definition is loaded.) A clear separation for scripts between load time and run time is a win. Also with this method, we can treat (specially marked) namespaces that have already been loaded into Clojure as runnable entities (albeit with a rather restricted interface for arguments and return values). We can invoke them from other Clojure code as we would in a shell script, but without involving the OS at all. Via string arguments, these Clojure scripts could also indicate/react- to a desire to use *in* *out* and *err* to communicate as corresponding UNIX tools would when run by the shell. People who want to "run code from a file" will still be able to do so by using "load", but that would no longer be the supported mechanism for writing/using/invoking Clojure scripts. Thoughts? --Steve
smime.p7s
Description: S/MIME cryptographic signature