:use feature requests

3 views
Skip to first unread message

Chouser

unread,
Feb 23, 2009, 1:54:31 PM2/23/09
to clo...@googlegroups.com
I have a feature request for the 'use' function. First an example. I
have some real-world code like this:

(ns n01se.net.graph.issues
(:import (java.text SimpleDateFormat ParsePosition)
(java.util GregorianCalendar Calendar)
(org.jfree.chart ChartFrame))
(:use [clojure.zip :only (xml-zip node)]
[clojure.contrib.lazy-xml :only (parse-trim)]
[clojure.contrib.zip-filter.xml :only (xml-> attr text)]
[clojure.contrib.seq-utils :only (reductions)])
(:require [clojure.contrib.zip-filter :as zf]
[com.markmfredrickson.dejcartes :as chart]))

It struck me as awkward that libs are separated into :use and :require
blocks when I need almost the same thing from each. In fact, any one
lib has a tendency to be shuffled between the two as I tidy up usages
in the code and change my mind about whether I want the whole
namespace aliased or specific functions brought in.

After kicking around some alternatives, I realized 'use' is sufficient
for all cases:

(ns n01se.net.graph.issues
(:import (java.text SimpleDateFormat ParsePosition)
(java.util GregorianCalendar Calendar)
(org.jfree.chart ChartFrame))
(:use [clojure.zip :only (xml-zip node)]
[clojure.contrib.zip-filter :as zf :only ()]
[clojure.contrib.zip-filter.xml :only (xml-> attr text)]
[clojure.contrib.lazy-xml :only (parse-trim)]
[clojure.contrib.seq-utils :only (reductions)]
[com.markmfredrickson.dejcartes :as chart :only ()]))

This is much prettier to my eye, but has a couple things that could be
better. So, feature request #1 is that if a libspec has an ":as"
option, that the ":only []" option be implied. That is, if I'm
aliasing an namespace, don't by default refer in all that namespaces
vars.

While this would technically be a breaking change, it seems unlikely
to me that it will cause much if any real-world disruption. Any usage
that actually intended to both alias the namespace and refer all the
symbols could say [my.lib :as mylib :exclude ()]

--Chouser

Stephen C. Gilardi

unread,
Feb 23, 2009, 2:33:45 PM2/23/09
to clo...@googlegroups.com

On Feb 23, 2009, at 1:54 PM, Chouser wrote:

> After kicking around some alternatives, I realized 'use' is sufficient
> for all cases:
>
> (ns n01se.net.graph.issues
> (:import (java.text SimpleDateFormat ParsePosition)
> (java.util GregorianCalendar Calendar)
> (org.jfree.chart ChartFrame))
> (:use [clojure.zip :only (xml-zip node)]
> [clojure.contrib.zip-filter :as zf :only ()]
> [clojure.contrib.zip-filter.xml :only (xml-> attr text)]
> [clojure.contrib.lazy-xml :only (parse-trim)]
> [clojure.contrib.seq-utils :only (reductions)]
> [com.markmfredrickson.dejcartes :as chart :only ()]))
>
> This is much prettier to my eye, but has a couple things that could be
> better. So, feature request #1 is that if a libspec has an ":as"
> option, that the ":only []" option be implied. That is, if I'm
> aliasing an namespace, don't by default refer in all that namespaces
> vars.
>
> While this would technically be a breaking change, it seems unlikely
> to me that it will cause much if any real-world disruption. Any usage
> that actually intended to both alias the namespace and refer all the
> symbols could say [my.lib :as mylib :exclude ()]

I like this a lot.

At that point, it seems only a small step to remove "require" entirely
which I think would be a long-term plus--coalescing two very similar
things (require and use) into one (use) with (possibly) an additional
option.

In order to keep it clear what non-core symbols refer to, several of
us have been recommending always using either :as or :only and only
very rarely if ever a "naked" use.

How about this as an alternative in the same spirit as your proposal:

- change the name of :require to :use -- :use with no options changes
from an implicit "refer all" to an implicit "refer none"

- :as, :only, :exclude, and :rename work as they do now

- add an :all option to cover the case of really wanting to refer in
all of the subject namespace. It would have the same effect as
":exclude ()". (Alternatively, perhaps we intend for this to be a rare
enough use case that ":exclude ()" by itself would suffice.)

Of course this would be a bigger, definitely breaking change, but not
breakage that will be at all difficult to find or fix in old or new
code.

--Steve

Chouser

unread,
Feb 23, 2009, 2:59:17 PM2/23/09
to clo...@googlegroups.com
On Mon, Feb 23, 2009 at 2:33 PM, Stephen C. Gilardi <sque...@mac.com> wrote:
>
> At that point, it seems only a small step to remove "require" entirely which
> I think would be a long-term plus--coalescing two very similar things
> (require and use) into one (use) with (possibly) an additional option.
>
> In order to keep it clear what non-core symbols refer to, several of us have
> been recommending always using either :as or :only and only very rarely if
> ever a "naked" use.
>
> How about this as an alternative in the same spirit as your proposal:
>
> - change the name of :require to :use -- :use with no options changes
> from an implicit "refer all" to an implicit "refer none"
>
> - :as, :only, :exclude, and :rename work as they do now
>
> - add an :all option to cover the case of really wanting to refer in
> all of the subject namespace. It would have the same effect as ":exclude
> ()". (Alternatively, perhaps we intend for this to be a rare enough use case
> that ":exclude ()" by itself would suffice.)
>
> Of course this would be a bigger, definitely breaking change, but not
> breakage that will be at all difficult to find or fix in old or new code.

I'm completely in favor of all of this -- let's do it!

--Chouser

Vincent Foley

unread,
Feb 23, 2009, 3:17:28 PM2/23/09
to Clojure
Stuart is gonna love you guys ;)

On Feb 23, 2:59 pm, Chouser <chou...@gmail.com> wrote:

James Reeves

unread,
Feb 23, 2009, 3:29:16 PM2/23/09
to Clojure
On Feb 23, 6:54 pm, Chouser <chou...@gmail.com> wrote:
> (ns n01se.net.graph.issues
>   (:import (java.text SimpleDateFormat ParsePosition)
>            (java.util GregorianCalendar Calendar)
>            (org.jfree.chart ChartFrame))
>   (:use [clojure.zip                    :only (xml-zip node)]
>         [clojure.contrib.zip-filter     :as zf :only ()]
>         [clojure.contrib.zip-filter.xml :only (xml-> attr text)]
>         [clojure.contrib.lazy-xml       :only (parse-trim)]
>         [clojure.contrib.seq-utils      :only (reductions)]
>         [com.markmfredrickson.dejcartes :as chart :only ()]))

Whilst we're throwing out ideas, I almost wonder if it wouldn't be
worth allowing for this case in addition:

(ns foo.bar
(:use clojure.zip :only (xml-zip node))
(:use clojure.contrib.zip-filter :as zf))

It seems a little more aesthetically pleasing to me, and whilst it
would require a lookahead of 1 to watch for keywords, some of the
current binding syntax does the same.

- James

Cosmin Stejerean

unread,
Feb 23, 2009, 3:45:48 PM2/23/09
to clo...@googlegroups.com
On Mon, Feb 23, 2009 at 2:29 PM, James Reeves <weave...@googlemail.com> wrote:

On Feb 23, 6:54 pm, Chouser <chou...@gmail.com> wrote:
> (ns n01se.net.graph.issues
>   (:import (java.text SimpleDateFormat ParsePosition)
>            (java.util GregorianCalendar Calendar)
>            (org.jfree.chart ChartFrame))
>   (:use [clojure.zip                    :only (xml-zip node)]
>         [clojure.contrib.zip-filter     :as zf :only ()]
>         [clojure.contrib.zip-filter.xml :only (xml-> attr text)]
>         [clojure.contrib.lazy-xml       :only (parse-trim)]
>         [clojure.contrib.seq-utils      :only (reductions)]
>         [com.markmfredrickson.dejcartes :as chart :only ()]))

Whilst we're throwing out ideas, I almost wonder if it wouldn't be
worth allowing for this case in addition:

(ns foo.bar
 (:use clojure.zip :only (xml-zip node))
 (:use clojure.contrib.zip-filter :as zf))

+1

I think :as should be mutually exclusive with :only (and friends).

--
Cosmin Stejerean
http://offbytwo.com

Perry Trolard

unread,
Feb 23, 2009, 4:52:06 PM2/23/09
to Clojure
+1 from me, too.

As to an :all shortcut that's synonymous with :exclude (), I think
convenience at the REPL is a good argument for :all. (I'm assuming
that the `require` macro would disappear, too.)

For Cosmin's thought (:as mutually exclusive with :exclude, :only,
& :rename), it does seem to me that when one is aliasing a namespace,
one wouldn't have a need to exclude or rename any functions (because
there's no chance of conflict or namespace pollution). Does anyone
disagree?

I do like James Reeves suggestion, but only if it's easy enough to
implement; also, it seems mostly like a trade of outer parens for
inner brackets -- in the end you'll have the same number of wrapping
characters...

Perry


Cosmin Stejerean

unread,
Feb 23, 2009, 6:37:46 PM2/23/09
to clo...@googlegroups.com
On Mon, Feb 23, 2009 at 3:52 PM, Perry Trolard <tro...@gmail.com> wrote:

+1 from me, too.

As to an :all shortcut that's synonymous with :exclude (), I think
convenience at the REPL is a good argument for :all. (I'm assuming
that the `require` macro would disappear, too.)

For Cosmin's thought (:as mutually exclusive with :exclude, :only,
& :rename), it does seem to me that when one is aliasing a namespace,
one wouldn't have a need to exclude or rename any functions (because
there's no chance of conflict or namespace pollution). Does anyone
disagree?

The only reason I could see for using both :as and something :only is to bring certain vars from that namespace into the current one AND refer to that namespace by a shortname so you can access other parts of it. That can in fact happen sometimes but in those cases my recommendation would be to use to :use statements

:use foo.bar :only [eggs, spam]
:use foo.bar :as fb

wlr

unread,
Feb 23, 2009, 10:24:17 PM2/23/09
to Clojure
On Feb 23, 2:59 pm, Chouser <chou...@gmail.com> wrote:
> On Mon, Feb 23, 2009 at 2:33 PM, Stephen C. Gilardi <squee...@mac.com> wrote:
> > How about this as an alternative in the same spirit as your proposal:
>
> >        - change the name of :require to :use -- :use with no options changes
> > from an implicit "refer all" to an implicit "refer none"
>
> >        - :as, :only, :exclude, and :rename work as they do now
>
> >        - add an :all option to cover the case of really wanting to refer in
> > all of the subject namespace. It would have the same effect as ":exclude
> > ()". (Alternatively, perhaps we intend for this to be a rare enough use case
> > that ":exclude ()" by itself would suffice.)
>
> > Of course this would be a bigger, definitely breaking change, but not
> > breakage that will be at all difficult to find or fix in old or new code.
>
> I'm completely in favor of all of this -- let's do it!

Shouldn't you say, "all of this and more"? Wouldn't the require and
use *functions* need some compatible changes?

Walt

Stephen C. Gilardi

unread,
Feb 24, 2009, 8:02:39 PM2/24/09
to clo...@googlegroups.com

On Feb 23, 2009, at 1:54 PM, Chouser wrote:

> This is much prettier to my eye, but has a couple things that could be
> better. So, feature request #1 is that if a libspec has an ":as"
> option, that the ":only []" option be implied. That is, if I'm
> aliasing an namespace, don't by default refer in all that namespaces
> vars.

Making only the ":as x" implies ":only ()" change that you proposed
would make it easy and pretty for anyone following the style we've
been recommending to stick with ":use" exclusively even if ":require"
remains in Clojure.

> While this would technically be a breaking change, it seems unlikely
> to me that it will cause much if any real-world disruption. Any usage
> that actually intended to both alias the namespace and refer all the
> symbols could say [my.lib :as mylib :exclude ()]


Intentionally referring an entire namespace in and also aliasing it
seems a very odd thing to do. The number of libs this change would
break is very likely to be tiny and the breakage will be obvious and
easy to fix.

I've made the change you proposed on my machine and it works nicely.

Here is an updated doc for "use" as would be correct if this change
were adopted.

-------------------------
clojure.core/use
([& args])

Loads libs, skipping any that are already loaded. Provides
options to call clojure.core/alias or clojure.core/refer
for each lib's namespace. Each argument is either a
libspec that identifies a lib, a prefix list that
identifies multiple libs whose names share a common
prefix, or a flag that modifies how all the identified
libs are loaded.

Note: clojure.core/use exists primarily to implement the
:use clause in an ns form. Direct calls to
clojure.core/use are only appropriate in interactive
contexts such as at a REPL.

Libs

A lib is a named unit of Clojure code that defines a
namespace. Each lib is stored in one or more resources in
classpath.

Lib names are symbols and each lib is associated with the
Clojure namespace and the Java package that share its
name. Each lib is also associated with a
classpath-relative root path via Java's 'package name' to
'classpath-relative path' mapping.

For example, the classpath-relative root path for the lib
a.b-c.d is a/b_c/d. Given this root path, use will load
either the compiled resource a/b_c/d__init.class or the
Clojure source resource a/b_c/d.clj, preferring the
compiled resource if it's both present and has a later
modification date than the source resource.

A lib's source resource should begin with an ns form to
create the lib's namespace, declare and satisfy any
dependencies it has on other libs, and/or load any
additional resources.

Libspecs

A libspec is a lib name or a vector containing a lib name
followed by options expressed as sequential keywords and
values.

Recognized options: :as, :exclude, :only, :rename

:as takes a symbol as its value and makes that symbol an
alias to the lib's namespace in the current namespace.

:exclude, :only, :rename and their associated values are
passed along to clojure/refer and have the effect
documented there.

When no options are given, use will call
clojure.core/refer without options to refer the lib's
entire namespace into the current namespace.

Prefix Lists

It's common for a lib to depend on several libs whose
names share a common prefix. When specifying libs, prefix
lists can be used to reduce repetition. A prefix list
contains the shared prefix followed by libspecs with the
shared prefix removed from the lib names. After removing
the prefix, the names that remain must not contain any
periods.

Flags

A flag is a keyword.

Recognized flags: :reload, :reload-all, :verbose

:reload forces loading of all the identified libs even if
they are already loaded

:reload-all implies :reload and also forces loading of all
libs that the identified libs directly or indirectly
load via require or use

:verbose triggers printing information about each load,
alias, and refer

--Steve

Jason Wolfe

unread,
Mar 4, 2009, 10:10:57 PM3/4/09
to Clojure
> Intentionally referring an entire namespace in and also aliasing it
> seems a very odd thing to do. The number of libs this change would
> break is very likely to be tiny and the breakage will be obvious and
> easy to fix.

I just ran into an instance where I might want to do just this.

I have a file really/long/namespace/util.clj with a bunch of
utilities, structs, and method definitions. Following (what I gather
is) an accepted convention, these structs have a :class key that maps
to a namespace-qualified keyword.

Now, I have another file stuff.clj that builds upon all of the
contents of util.clj. So, I want to :use util.clj, pulling in all of
its utilities, but I'd also like to be able to refer to its namespace-
qualified keywords with the alias ::util/keyword rather
than :really.long.namespace.util/keyword. Is there a way for me to
do this under your proposal?

(Maybe my potential setup is a bad idea, I don't know ... anyway, the
situation reminded me of this thread so I thought I'd mention it).

Other than this possible (very minor) snag, I very much like the
proposals in this thread.

-Jason






Chouser

unread,
Mar 4, 2009, 11:46:48 PM3/4/09
to clo...@googlegroups.com
On Wed, Mar 4, 2009 at 10:10 PM, Jason Wolfe <jaw...@berkeley.edu> wrote:
>
> I have a file really/long/namespace/util.clj with a bunch of
> utilities, structs, and method definitions.  Following (what I gather
> is) an accepted convention, these structs have a :class key that maps
> to a namespace-qualified keyword.
>
> Now, I have another file stuff.clj that builds upon all of the
> contents of util.clj.  So, I want to :use util.clj, pulling in all of
> its utilities, but I'd also like to be able to refer to its namespace-
> qualified keywords with the alias ::util/keyword rather
> than :really.long.namespace.util/keyword.   Is there a way for me to
> do this under your proposal?

Well, there's been two proposals. In my original less radical one,
I already addressed this requirement. For your example:

(ns util
(:use [really.long.namespace.util :as util :exclude ()]))

It looks a little awkward, but it's an unusual case. The common case
would become the prettier. And it has the benefit of working both now
and if the proposal is in effect.

Adding an :all option as Steve suggests would clean this up even more:

(ns util
(:use [really.long.namespace.util :as util :all]))

That change would of course break nothing.

The only behavior that would change with those two features would be
if somebody was currently doing:

(ns util
(:use [really.long.namespace.util :as util]))

...and they were actually relying on both the util alias *and* the
fact that all the util names were refer'ed in. I dare say that would
not break much existing code, and if it did would be easy to track
down and fix (by simply adding :all).

--Chouser

Stephen C. Gilardi

unread,
Mar 5, 2009, 12:00:55 AM3/5/09
to clo...@googlegroups.com

On Mar 4, 2009, at 11:46 PM, Chouser wrote:

> Adding an :all option as Steve suggests would clean this up even more:
>
> (ns util
> (:use [really.long.namespace.util :as util :all]))

I looked into this further after suggesting it and was reminded that
it would be difficult to support an option like :all that takes no
argument. Within a libspec, everything after the first item is a
sequential keyword and value.

I think :exclude () for that unusual case would be just fine.

--Steve

Jason Wolfe

unread,
Mar 5, 2009, 3:00:06 AM3/5/09
to clo...@googlegroups.com
Thanks, Steve and Chouser!

> Well, there's been two proposals. In my original less radical one,
> I already addressed this requirement. For your example:
>
> (ns util
> (:use [really.long.namespace.util :as util :exclude ()]))
>

That would be perfectly fine with me.

I just wanted to mention the use case, since I hadn't seen it
mentioned elsewhere in the thread (and didn't really understand why
anyone would want to both refer to and alias a namespace until this
came up.)

Cheers, Jason

Chouser

unread,
Mar 5, 2009, 8:50:53 AM3/5/09
to clo...@googlegroups.com

Aren't there already no-arg options like :reload and :verbose?

--Chouser

Stephen C. Gilardi

unread,
Mar 5, 2009, 9:00:33 AM3/5/09
to clo...@googlegroups.com

On Mar 5, 2009, at 8:50 AM, Chouser wrote:

> Aren't there already no-arg options like :reload and :verbose?

Those apply to the entire :use or :require clause. They are flags that
are peers with libspecs, not within them.

--Steve

Chouser

unread,
Mar 5, 2009, 9:24:31 AM3/5/09
to clo...@googlegroups.com

Fair enough.

So the least-breaking change proposed here would be simply that if
:use is given an :as parameter, that it no longer also refer all the
other symbols directly.

Rich seemed to want to reduce the breakage here as much as possible,
and IMHO this is pretty minimal.

If it's still too much potential breakage this behavior could be
attached to a new top-level name such as :uses or :demand, to be a new
sibling of :use and :require.

Perhaps gentle suggestions in the docs could then encourage people to
stop using the older forms such that they could one day be removed.

--Chouser

Jonathan Tran

unread,
Mar 5, 2009, 10:50:27 AM3/5/09
to Clojure
On Mar 5, 9:24 am, Chouser <chou...@gmail.com> wrote:

> So the least-breaking change proposed here would be simply that if
> :use is given an :as parameter, that it no longer also refer all the
> other symbols directly.
>
> Rich seemed to want to reduce the breakage here as much as possible,
> and IMHO this is pretty minimal.
>
> If it's still too much potential breakage this behavior could be
> attached to a new top-level name such as :uses or :demand, to be a new
> sibling of :use and :require.

No!!! Please, not _another_ namespace function. I find all the
namespace stuff in Clojure to be overly complicated already. To
newcomers, it must be utterly confusing... with ns, use, import,
require, refer, and then all the ns-* and *-ns stuff.

I think collapsing :use and :require into :use is a great idea.
Before I completely understood it, the proposed idea is how I
expected :use to work in the first place -- not dumping everything in
your namespace when you say :as.

As for not wanting to make breaking changes... I'm a little baffled by
this considering the whole laziness changes broke my code in _much_
more subtle ways. My two cents is that if we're going to make
breaking changes at all, let's do them right, and not introduce yet
more cruft with another function.

Jonathan

Stuart Sierra

unread,
Mar 5, 2009, 3:10:24 PM3/5/09
to Clojure
On Mar 5, 10:50 am, Jonathan Tran <jonnyt...@gmail.com> wrote:
> No!!!  Please, not _another_ namespace function.  I find all the
> namespace stuff in Clojure to be overly complicated already.  To
> newcomers, it must be utterly confusing... with ns, use, import,
> require, refer, and then all the ns-* and *-ns stuff.
>
> I think collapsing :use and :require into :use is a great idea.

Seconded.
-Stuart Sierra

Laurent PETIT

unread,
Mar 5, 2009, 4:16:23 PM3/5/09
to clo...@googlegroups.com

2009/3/5 Jonathan Tran <jonn...@gmail.com>


On Mar 5, 9:24 am, Chouser <chou...@gmail.com> wrote:

> So the least-breaking change proposed here would be simply that if
> :use is given an :as parameter, that it no longer also refer all the
> other symbols directly.
>
> Rich seemed to want to reduce the breakage here as much as possible,
> and IMHO this is pretty minimal.
>
> If it's still too much potential breakage this behavior could be
> attached to a new top-level name such as :uses or :demand, to be a new
> sibling of :use and :require.

No!!!  Please, not _another_ namespace function.  

+1
 
I find all the
namespace stuff in Clojure to be overly complicated already.  To
newcomers, it must be utterly confusing... with ns, use, import,
require, refer, and then all the ns-* and *-ns stuff.

I think collapsing :use and :require into :use is a great idea.
+1
 

Before I completely understood it, the proposed idea is how I
expected :use to work in the first place -- not dumping everything in
your namespace when you say :as.

As for not wanting to make breaking changes... I'm a little baffled by
this considering the whole laziness changes broke my code in _much_
more subtle ways.  My two cents is that if we're going to make
breaking changes at all, let's do them right, and not introduce yet
more cruft with another function.

Agreed.
 


Jonathan




Reply all
Reply to author
Forward
0 new messages