On Jan 23, 2009, at 7:12 PM, e wrote:
first explicit question: after the example lib and the bullets, I don't see why there are two different keywords, "use" and "require". Just look at the start of the sentences. They are identical. Why not just pick one of the two keywords and let "only" be a modifier when you want only certain things, and "as" be a modifier when you still want some level of qualification?
First some background:A map maintains relations between keys and values such that given a key, it can return the associated value.
Every namespace contains a map from symbols to the vars or classes they represent. You can see that map for a particular namespace using ns-map. For example:
(ns-map 'user)
When the compiler sees a symbol it "resolves" it to determine which
var or class it represents. If the symbol has no namespace part, one
of the steps in resolving is to check the ns-map for the current
namespace. For example:
user=> (get (ns-map 'user) 'prn)
#'clojure.core/prn
This result indicates that in the namespace user, the symbol prn
resolves to the var #'clojure.core/prn.
How did it come to pass that the ns-map for 'user contains a reference to a var in the clojure.core namespace? That kind of reference is made by clojure.core/refer which you should read about. Soon after the user namespace is created, the code that creates it calls (effectively) "(refer 'clojure.core)".
Now about require and use:
require - ensures that a lib is loaded
refer - makes entries in this namespace's ns-map that are identical
to (or based on) entries in the ns-map of another namespace
use - first require, then refer
It would be technically feasible to get rid of "use" and only allow
require and refer. It would also be feasible to add keyword commands
to require that would accomplish the refer function without an
explicit call to refer. The reason we have both require and use (and
therefore :require and :use) is that when this was being designed,
"require followed by refer" was thought to be a common enough case to
warrant a name of its own.
Subsequent to the introduction of require, use, and ns, several folks noted that one can refer to other code in an "ns" form either in a way that makes it explicit what you're bringing into the new namespace or in a way that leaves it implicit. There is a preference in the example at clojure.org/libs for the style that makes the name(s) explicit.
Here's the implicit way:
(ns mertz.fred
(:use clojure.contrib.sql)
(:use org.desilu.french))
This is convenient in that any names defined in namespace
clojure.contrib.sql can be used in the subsequent code without any
namespace qualification, for example:
(with-connection my-db
[...])
In this call, with-connection resolves to #'clojure.contrib.sql.with-
connection, but that's not apparent just by reading the code.
Here's the corresponding explicit way:
(ns mertz.fred
(:use [clojure.contrib.sql :only (with-connection)])
(:use [org.desilu.french :only (grey-poupon)]))
Now it's easy to see where with-connection comes from by examining the
ns form.
Being explicit takes some more work and thought and maintenance, but it does make things easier on future readers of the code.
Alternatively, if you want to bring in everything from another namespace, but still be able to tell which symbols come from which places, you can use a namespace alias to shorten up the name. It would be a real drag to type clojure.contrib.sql/with-connection every time you want to call it. However, some short prefix like "sql" wouldn't be too bad. Using a namespace alias for this looks like this:
(ns mertz.fred
(:require [clojure.contrib.sql :as sql])
(:use [org.desilu.french :only (grey-poupon)]))
Now at the site of the call, it's clear where with-connection came from:
(sql/with-connection my-db
[...])
With this method, the ns-map of mertz.fred has no entries that refer
to vars in clojure.contrib.sql.
Why not just pick one of the two keywords and let "only" be a modifier when you want only certain things, and "as" be a modifier when you still want some level of qualification?
It's certainly desirable to have a require that doesn't do a refer. Between require and use, require is the more basic of the two and would not go away.
To get rid of :use, it would be feasible to modify :require such that the appearance of :only, :exclude, or :rename would imply a "refer". At that point you could do what you're asking about. For cases where :only, :exclude, or :rename are desired, you could use them. For the case of bringing in the entire namespace you could write:
(:require [clojure.contrib.sql :exclude ()])
or
(:require [clojure.contrib.sql :rename ()])
Of those, the "exclude" version is easier to understand, but still a
bit awkward. Note that it wouldn't fit in easily to write (something
like)
(:require [clojure.contrib.sql :all])
because all the arguments to require after the first are keyword-value
pairs. One could say ":all true" or ":refer :all" but that's pretty
awkward as well.
Given that it's feasible to remove "use" and ":use", the next question is whether or not it's desirable. I think "use" and ":use" are succinct and convenient, provide a non-awkward way to bring in an entire namespace's mappings, and I like the added flexibility they provide over other options such as having only "require" and ":require" or introducing ":refer".
--Steve
smime.p7s
Description: S/MIME cryptographic signature
