lib.clj questions

3 views
Skip to first unread message

Chas Emerick

unread,
Jun 28, 2008, 8:42:19 AM6/28/08
to Clojure
I'm just now looking at lib.clj -- having a couple of issues, though.
I feel like I must be missing something fundamental. My questions:

(a) The docs in lib.clj imply that require should fail if it can't
load a library (e.g. "ensures that the specified libs are loaded").
Even if I'm misreading that, shouldn't require fail (or optionally
fail?) if the libspec cannot be resolved?

(b) What's the correct incantation to get require/use to grab a
library from a package? I have foo.clj in com/pkg, and none of these
seem to work: (use com.pkg.foo) (use "com.pkg.foo") (use 'com.pkg.foo)
(use "com/pkg/foo") (use (symbol "com/pkg/foo")), etc.

Thanks,

-Chas

Stephen C. Gilardi

unread,
Jun 28, 2008, 9:46:27 AM6/28/08
to clo...@googlegroups.com
> I'm just now looking at lib.clj -- having a couple of issues, though.
> I feel like I must be missing something fundamental. My questions:

Hi Chas,

Thanks for looking.

> (a) The docs in lib.clj imply that require should fail if it can't
> load a library (e.g. "ensures that the specified libs are loaded").
> Even if I'm misreading that, shouldn't require fail (or optionally
> fail?) if the libspec cannot be resolved?

You're right. That's a bug: a regression from previous behavior when
I tried to simplify the code that does the loading by using
"loadResourceScript". I'll restore the old behavior today. I asked
Rich to give me some way to know that loadResourceScript failed and
he's OK with that so that should appear at some point.

> (b) What's the correct incantation to get require/use to grab a
> library from a package? I have foo.clj in com/pkg, and none of these
> seem to work: (use com.pkg.foo) (use "com.pkg.foo") (use 'com.pkg.foo)
> (use "com/pkg/foo") (use (symbol "com/pkg/foo")), etc.

The correct incantation is:

(use (foo :in "com/package"))

There are some examples in the documentation at the top of "lib.clj".

' sorry I missed you in #clojure. Thanks for following up here!

--Steve

Chas Emerick

unread,
Jun 28, 2008, 1:14:28 PM6/28/08
to Clojure


On Jun 28, 9:46 am, "Stephen C. Gilardi" <scgila...@gmail.com> wrote:
> > I'm just now looking at lib.clj -- having a couple of issues, though.
> > I feel like I must be missing something fundamental. My questions:
>
> Hi Chas,
>
> Thanks for looking.
>
> > (a) The docs in lib.clj imply that require should fail if it can't
> > load a library (e.g. "ensures that the specified libs are loaded").
> > Even if I'm misreading that, shouldn't require fail (or optionally
> > fail?) if the libspec cannot be resolved?
>
> You're right. That's a bug: a regression from previous behavior when
> I tried to simplify the code that does the loading by using
> "loadResourceScript". I'll restore the old behavior today. I asked
> Rich to give me some way to know that loadResourceScript failed and
> he's OK with that so that should appear at some point.

OK, sounds good.

> > (b) What's the correct incantation to get require/use to grab a
> > library from a package? I have foo.clj in com/pkg, and none of these
> > seem to work: (use com.pkg.foo) (use "com.pkg.foo") (use 'com.pkg.foo)
> > (use "com/pkg/foo") (use (symbol "com/pkg/foo")), etc.
>
> The correct incantation is:
>
> (use (foo :in "com/package"))
>
> There are some examples in the documentation at the top of "lib.clj".

Yeah, I saw that, but it didn't work for me until I realized that use
would attempt to refer to foo here, rather than the com.package.foo
namespace, which is what I was expecting. Redirecting me back to
those docs got me to notice the :ns flag again; this works:

(lib/use (foo :in "pkg.bar" :ns pkg.bar.foo))

This is pretty ugly, simply because my foo.clj file is defining a
namespace that mirrors where it sits in Java's package structure. I
wouldn't bother with doing this, except that (a) this is a "mixed"
project, with clojure, Java, and clojure-generated-Java-classfiles
floating around, and (b) the codebase isn't/won't be small, and using
directories to define package/namespace structure (by default) is a
reasonable approach, IMO. This goes back to this discussion I noticed
earlier this morning:

http://groups.google.com/group/clojure/tree/browse_frm/thread/9a45568453df23de/30f8988751c7e0e4?rnum=1&q=hierarchical+package+names&_done=%2Fgroup%2Fclojure%2Fbrowse_frm%2Fthread%2F9a45568453df23de%2Fda858386ff7e48fc%3Flnk%3Dgst%26q%3Dhierarchical%2Bpackage%2Bnames%26#doc_e4b5995b47f42b2c

This is a good "debate" to have -- how closely clojure should hew to
Java conventions outside of those required by the JVM itself.

> ' sorry I missed you in #clojure. Thanks for following up here!

I'm sure we'll run into each other eventually. Thank you for your
help, and your contributions; I've been trying to slip helpful
questions out there as I go along. Hopefully the archived solutions
will be helpful to others, too.

- Chas

Stuart Sierra

unread,
Jun 30, 2008, 12:51:10 PM6/30/08
to Clojure
On Jun 28, 1:14 pm, Chas Emerick <cemer...@snowtide.com> wrote:
> (lib/use (foo :in "pkg.bar" :ns pkg.bar.foo))
>
> This is pretty ugly, simply because my foo.clj file is defining a
> namespace that mirrors where it sits in Java's package structure. I
> wouldn't bother with doing this, except that (a) this is a "mixed"
> project, with clojure, Java, and clojure-generated-Java-classfiles
> floating around, and (b) the codebase isn't/won't be small, and using
> directories to define package/namespace structure (by default) is a
> reasonable approach, IMO. This goes back to this discussion I noticed
> earlier this morning:
>
> http://groups.google.com/group/clojure/tree/browse_frm/thread/9a45568...
>
> This is a good "debate" to have -- how closely clojure should hew to
> Java conventions outside of those required by the JVM itself.


Hi Chas, Stephen, and all,

I know everybody hates Java's package/directory/hierarchy, but the
fact is that it works.

I think the recent addition of gen-and-save-class makes a compelling
argument for following this Java convention in Clojure code. And I
would venture a guess that a lot of Clojure users will be running a
mixed environment similar to what Chas describes.

So if the namespace foo.bar.baz is defined at CLASSPATH/foo/bar/
baz.clj, what are the downsides?

The biggest nuisance I can see is when you want to utilize a namespace
but not "refer" it -- you'll be typing "foo.bar.baz/quux" a lot.
Could we have namespace aliases? I.e. (refer 'foo.bar.baz :as 'baz),
then call baz/quux ?

-Stuart

Rich Hickey

unread,
Jun 30, 2008, 1:03:12 PM6/30/08
to Clojure


On Jun 30, 12:51 pm, Stuart Sierra <the.stuart.sie...@gmail.com>
wrote:
We had a chat about this on the IRC today, where I concurred with the
above.

Probably won't happen until I get back from ECOOP.

Rich

Scott Parish

unread,
Jul 1, 2008, 12:00:04 AM7/1/08
to clo...@googlegroups.com
On Mon, Jun 30, 2008 at 09:51:10AM -0700, Stuart Sierra wrote:

> The biggest nuisance I can see is when you want to utilize a namespace
> but not "refer" it -- you'll be typing "foo.bar.baz/quux" a lot.
> Could we have namespace aliases? I.e. (refer 'foo.bar.baz :as 'baz),
> then call baz/quux ?

It might be nice to have first class namespaces. You could then "alias"
by simply assigning to a var. Further, you could then do things like
use the 'binding' macro to redirect existing code to use alternative
namespaces.

sRp


Chas Emerick

unread,
Jul 1, 2008, 6:11:46 AM7/1/08
to Clojure
That sounds really fantastic. I'll bet that it won't happen, at least
not in the near-term -- I can see how doing so could make namespace
lookup a lot slower than the current implementation.

FWIW, Clojure is a Lisp-1, so you can do things like this already
using maps of strings to functions:

(def semi-ns {"bar" (fn [] ...) "foo" (fn [] ...})

((semi-ns "bar") .....)

(binding [semi-ns some-other-ns]
((semi-ns "bar") ....))

You could go one further with a macro that replaces any keywords in
function position with the appropriate semi-ns lookup:

(ns-map-macro [semi-ns some-other-ns]
("bar" .....))

A more robust approach might be to have a macro that creates,
populates, and then deletes a uniquely-named scratch namespace.

This is all a little hand-wavy, but it's certainly *sounds*
doable. ;-)

- Chas

Rich Hickey

unread,
Jul 1, 2008, 8:03:53 AM7/1/08
to Clojure


On Jul 1, 12:00 am, Scott Parish <s...@srparish.net> wrote:
That would involve runtime lookup, which Clojure currently avoids.

A namespace is truly just part of a name (vs, say, a module, or
environment), one for which there is a convention for omission. They
are reified to allow for runtime compilation and reflection, but are
not runtime lookup environments otherwise. Doing so would not make
them any more "first class", it would just be a different (2-stage, ns-
>name->) location model.

Clojure avoids that model for speed (being a 1-stage, name->, location
model means the locations (vars) can be compiled into the code, and
are), and will continue to do so.

Rich

Scott Parish

unread,
Jul 1, 2008, 10:59:49 AM7/1/08
to clo...@googlegroups.com

I don't see how this would be that much slower, especially since most
people would probably dereference away the other namespace well before
entering performance sensitive loops. For instance:

(def baz (-> foo (:bar) (:baz)))

(defn my-loop [x]
...
(recur (baz x)))

sRp

Rich Hickey

unread,
Jul 1, 2008, 12:52:16 PM7/1/08
to Clojure
Right now, if in a function baz you refer to foo/bar (after
resolution, not necessarily explicitly), the compiler need only
generate code that will produce the current value of 'foo/bar'. If
namespaces become independent parts of the resolution path, then a
reference to foo/bar will require the compiler to generate code that
will produce the current value of 'bar' in the current value of 'foo',
i.e. 2 hops, the second of which must be a lookup. That will
definitely be slower. There can be no redirection without indirection.

What you are doing above is just aliasing, which is a simpler problem.

Currently, you can do refer with renaming. What you can't emulate is:

(refer 'some-really-long-ns :as 'srln)

which I hope to add. But it will only be aliasing, and will not
introduce 2-stage lookup.

Rich


Reply all
Reply to author
Forward
0 new messages