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
