Coding Standard - ns usage

467 views
Skip to first unread message

David McNeil

unread,
Nov 8, 2012, 11:57:20 AM11/8/12
to clo...@googlegroups.com
I notice the following item at http://dev.clojure.org/display/design/Library+Coding+Standards

   "Be explicit and minimalist about dependencies on other packages. (Prefer the :only option to use and require)."

The page was last edited on Mar 29, 2011 and ns usage has been discussed a fair bit since then... this leads to the question:

   Is the item quoted above still the standard for Clojure Libraries?

Thanks.
-David

Jim - FooBar();

unread,
Nov 8, 2012, 12:03:27 PM11/8/12
to clo...@googlegroups.com
I'm pretty sure this is still valid
:)

Jim
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient
> with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en

László Török

unread,
Nov 8, 2012, 12:33:42 PM11/8/12
to clo...@googlegroups.com

Hi,

I thought :require with :refer superseded :use :only.

Or am I mistaken?

Las

On Nov 8, 2012 6:03 PM, "Jim - FooBar();" <jimpi...@gmail.com> wrote:
I'm pretty sure this is still valid
:)

Jim

On 08/11/12 16:57, David McNeil wrote:
I notice the following item at http://dev.clojure.org/display/design/Library+Coding+Standards

   "Be explicit and minimalist about dependencies on other packages. (Prefer the :only option to use and require)."

The page was last edited on Mar 29, 2011 and ns usage has been discussed a fair bit since then... this leads to the question:

   Is the item quoted above still the standard for Clojure Libraries?

Thanks.
-David
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

Justin Kramer

unread,
Nov 8, 2012, 12:52:20 PM11/8/12
to clo...@googlegroups.com
Current best practice in my view:

For Clojure 1.4+, do not use :use at all. Use :require :refer (judiciously). :refer :all is almost never a good idea.

For Clojure 1.3 and below, :use :only is strongly encouraged. Bare :use is almost never good.

Justin

Softaddicts

unread,
Nov 8, 2012, 1:39:53 PM11/8/12
to clo...@googlegroups.com
I am pragmatic and quite lazy, I use require with an alias and use mostly with stuff like
clojure.tools.trace, clojure.pprint where selecting explicit vars brings
no or little value (in my opinion).
You either need most of the public vars or the potential name conflict is a remote
possibility a few light-years away.

I almost never select explicit vars from external name spaces. I find this cumbersome to manage.

With (short) aliases, I get auto expansion of all public vars as soon as I type the /
in CCW (Eclipse plugin). With a little consistency in choosing aliases,
it's then very easy to find out while reading the code where a reference comes from.

I am also older than most of you guys so the less stuff resides in my working memory,
the easier I can cheat with the slowly eroding aging process :)
I leave most of the work to the computer.

Mmmh, maybe I should create a pocket guide for elderly Clojure coders someday...

Luc P.
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
--
Softaddicts<lprefo...@softaddicts.ca> sent by ibisMail from my ipad!

Justin Kramer

unread,
Nov 8, 2012, 1:54:38 PM11/8/12
to clo...@googlegroups.com
Sorry, yes, to clarify -- :require :as is always good and generally preferred over :refer or :use :only.

Justin

Stefan Kamphausen

unread,
Nov 8, 2012, 5:45:41 PM11/8/12
to clo...@googlegroups.com
Am Donnerstag, 8. November 2012 19:42:26 UTC+1 schrieb Luc:
I am pragmatic and quite lazy, I use require with an alias

inc

An explicit call to use every now and then on the REPL, but no :use in ns.  IMHO use and :use can be removed from the language.

Softaddicts

unread,
Nov 8, 2012, 6:19:09 PM11/8/12
to clo...@googlegroups.com
1/2 +

Use is still a short way of including mundane stuff like tools.trace and a few
others. We leave :use .... clojure.tools.trace in place in namespaces once we have done
it.

Doing it in the REPL each time we need it while debugging is tedious.

Oh, I must say that I rarely use the Eclipse debugger. Tracing does most of the job.
Removing use would force us to redefine it somehow.

And yes I know how to use a debugger, even non-symbolic ones :)

Luc P.

Takahiro Hozumi

unread,
Nov 8, 2012, 7:23:46 PM11/8/12
to clo...@googlegroups.com
> :require :as is always good and generally preferred over :refer or :use :only.
I think we all agree with this, but in reality :use with/without :only is very widely used in a number of real project I've seen on github.
:use (especially without :only) makes code reading painful and usually reading time including other's is much longer than writing time.
I hope :use is used only for popular library such as clojure.test, etc.

Sean Corfield

unread,
Nov 9, 2012, 11:28:39 AM11/9/12
to clo...@googlegroups.com
On Thu, Nov 8, 2012 at 3:19 PM, Softaddicts <lprefo...@softaddicts.ca> wrote:
> Oh, I must say that I rarely use the Eclipse debugger. Tracing does most of the job.
> Removing use would force us to redefine it somehow.

(:use clojure.tools.trace) => (:require [clojure.tools.trace :refer :all)
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

Sean Corfield

unread,
Nov 9, 2012, 11:30:10 AM11/9/12
to clo...@googlegroups.com
On Fri, Nov 9, 2012 at 8:28 AM, Sean Corfield <seanco...@gmail.com> wrote:
> On Thu, Nov 8, 2012 at 3:19 PM, Softaddicts <lprefo...@softaddicts.ca> wrote:
>> Removing use would force us to redefine it somehow.
> (:use clojure.tools.trace) => (:require [clojure.tools.trace :refer :all)

*sigh* no paredit in Gmail and I haven't had my coffee yet:

(ns ...
(:use clojure.tools.trace) => (:require [clojure.tools.trace :refer :all])
...)

but I'm sure y'all knew what I meant.

Softaddicts

unread,
Nov 9, 2012, 1:07:23 PM11/9/12
to clo...@googlegroups.com
Yep but still longer to type :) we are in the process of shrinking the code base,
nit expanding it, any bytes count :))

Denis Labaye

unread,
Nov 10, 2012, 11:49:43 PM11/10/12
to clo...@googlegroups.com
Talking about `use` and `require`: 

How are you dealing with the repetition of each namespace "configuration"?

Each time I create a new namespace I add the following boilerplate: 

(ns foo.bar
  (:use      [clojure
             [pprint :only [pprint pp]]
             [repl :only [doc find-doc apropos]]]
            [clojure.java.javadoc :only [javadoc]]
            [clojure.tools.trace :only [trace deftrace trace-forms trace-ns untrace-ns trace-vars]])
  (:require [clojure
             [set :as set]
             [string :as str]
             [xml :as xml]]
            [clojure.java
             [shell :as sh]
             [io :as io]]))

How do you avoid repeating this ? A clojure macro?, IDE support?, ... ?

Ambrose Bonnaire-Sergeant

unread,
Nov 10, 2012, 11:53:19 PM11/10/12
to clo...@googlegroups.com
Convert (:use [lib :only [...]]) => (:require [lib :refer [...] :as ...])

Softaddicts

unread,
Nov 11, 2012, 12:02:53 AM11/11/12
to clo...@googlegroups.com
How does that shrink his boilerplate ?

Why such a long boilerplate ? Do you need the string library everywhere ?
Why not drop :only ?

Luc P.

Ambrose Bonnaire-Sergeant

unread,
Nov 11, 2012, 12:26:19 AM11/11/12
to clo...@googlegroups.com
Sorry, read the question incorrectly.

David McNeil

unread,
Nov 11, 2012, 9:36:25 AM11/11/12
to clo...@googlegroups.com
I have not heard from anyone that http://dev.clojure.org/display/design/Library+Coding+Standards is out of date, so I take that to mean that the following is still the standard:


   "Be explicit and minimalist about dependencies on other packages. (Prefer the :only option to use and require)."

-David

Denis Labaye

unread,
Nov 11, 2012, 2:44:24 PM11/11/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 6:02 AM, Softaddicts <lprefo...@softaddicts.ca> wrote:
How does that shrink his boilerplate ?

Why such a long boilerplate ? Do you need the string library everywhere ?
Why not drop :only ?

oftentimes, I am at the REPL, and I know this particular function in clojure.set (or clojure,io, or ...) is exactly what I need
I want it at my fingertips, I don't want to break my flow and `require` it.

And when creating a new namespace, I don't know in advance what other namespaces I will need.
That's why I always paste the same boilerplate when creating a new namespace.

In Java land, all IDEs have shortcut to import classes at the time it's needed, maybe that's what I need (in Emacs in my case).

Luc Prefontaine

unread,
Nov 11, 2012, 3:35:21 PM11/11/12
to clo...@googlegroups.com
I just find this puzzling, the "coding standards" emphasizes reducing dependencies.
Now if you add dependencies in your boiler plate that may in fact not be used by the source code
in the current name space, how can a human reader understand your dependencies by reading the top nth lines of your source file ?

This will worsen as your boiler plate expands.

Why not require a utility name space (:use [my-boilerplate]) with a single public uniquely named macro
(zxcv or any adjacent keys on your keyboard that you find easy to type)
to get all that stuff on your behalf in the REPL ?

Include this systematically and just type (zxcv) at the REPL. If you want to avoid the typing while in dev mode,
add (zxcv) in the source code after the (ns) macro. It will require all the other things you need until you are done
with it. No need to type it in the REPL anymore.

Later on you can add the real dependencies in the ns macro. That can be the last step after your dev is done.
It should sum up to a few requires with aliases. The zxcv is still available (requiring twice the same name space
with the same alias has no bad effects) when you go back later at the REPL.

I maintain that once you require a name space, is entirely loaded so the explicit narrowing of function used
looks to me an overkill. Especially if you have an alias in your require call. There's no possible confusion with
an alias and calls are can easily be searched as text strings which all IDEs support.

Luc P.
--
Luc P.

================
The rabid Muppet

Softaddicts

unread,
Nov 11, 2012, 4:56:22 PM11/11/12
to clo...@googlegroups.com
Since you use emacs, why not create a key binding to an expression that would get
evaluated in the REPL ? or to eval the zxcv macro ?

Luc P.

Denis Labaye

unread,
Nov 11, 2012, 4:58:49 PM11/11/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 10:56 PM, Softaddicts <lprefo...@softaddicts.ca> wrote:
Since you use emacs, why not create a key binding to an expression that would get
evaluated in the REPL ? or to eval the zxcv macro ?

Luc P.

Luc, 

Yes, the solutions you described (Clojure utility macro, or Emacs key binding) are possible solutions to my "problem", but I was asking, because I thought I wasn't the only one to have this "issue".

Denis

Mark Engelberg

unread,
Nov 11, 2012, 5:26:03 PM11/11/12
to clo...@googlegroups.com
I can relate to Denis' issue.  I find it pretty common to have a common set of dependencies across every file in a project.  Copying and pasting this header to every file and updating changes manually across every file doesn't feel like a very robust solution.  This is something that has bothered me as well.

Brian Marick

unread,
Nov 11, 2012, 6:25:49 PM11/11/12
to clo...@googlegroups.com

On Nov 8, 2012, at 12:39 PM, Softaddicts wrote:

> Mmmh, maybe I should create a pocket guide for elderly Clojure coders someday...


An aside: I'm giving a keynote at the ACCU conference titled "Cheating Decline: Acting now to let you program well for a really long time" I'll be looking for people who can share (general purpose tricks of the aging trade). Contact me if interested.

-----
Brian Marick, Artisanal Labrador
Contract programming in Ruby and Clojure
Occasional consulting on Agile
Writing /Functional Programming for the Object-Oriented Programmer/: https://leanpub.com/fp-oo


Luc Prefontaine

unread,
Nov 11, 2012, 6:28:25 PM11/11/12
to clo...@googlegroups.com
This is the best I can come with in a short time:

(ns higiebus.services.depcy-profiles
"Shortcut to common dependency profile")

(defmacro basic-service-deps
[]
`(do
(require [higiebus.services.config :as conf] [higiebus.services.loggers :as log]
[clojure.string :as s])
(use [clojure.tools.trace])))

In the caller's name space:

(ns higiebus.services.aqueduct
"Implement sinks and risers as abstractions on top of concrete transports."
(:require [higiebus.adaptors.socket :as sock] [higiebus.services.queuemgr :as q])
(:use [higiebus.services.depcy-profiles]))

(basic-service-deps)

There is a bit of information loss but if the dependency profiles are correctly defined
it's probably bearable and not to numerous. I am juggling with the idea of using this in our code base.
Especially when using some service portfolios, we have to spell a litany of dependencies.

Now, how far should I go with this requires some thinking. I can probably represent profiles
as data and add some functions to report what they are made of, provide a single fn
to load profiles by name, allowing to compound them, ...

I'll play with this in the next couple of days.

Luc

Sean Corfield

unread,
Nov 11, 2012, 8:59:56 PM11/11/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 2:26 PM, Mark Engelberg
<mark.en...@gmail.com> wrote:
> I can relate to Denis' issue. I find it pretty common to have a common set
> of dependencies across every file in a project.

Well, I have to say I was puzzled by Denis' post because I definitely
don't have common dependencies across every file. Now hearing you say
the same thing I'm doubly puzzled...

I don't like to have anything imported that I'm not explicitly using
(and I regularly double-check after refactoring to make sure I remove
any redundant imports). Preferences aside, however, I'm genuinely
curious as to the sort of program structure that has the same
dependencies in every namespace. I can see how some of Denis' imports
are useful for the repl - but I tend to just import them as needed or
write them out in full (clojure.pprint/pprint is my most common one) -
but I'm a bit surprised to see set, string, xml, sh and io all being
that common (in every file).

Denis, Mark, could you speak to what sort of things you're using these
for that make it convenient to have them in every namespace?

I tend to have I/O isolated to one or two namespaces, the same goes
for shell operations, and XML operations. Maybe we're working in
different enough fields that our use cases are very different (I
suspect that's true for Mark - not sure what area Denis works in?).

Phil Hagelberg

unread,
Nov 11, 2012, 9:07:40 PM11/11/12
to clo...@googlegroups.com
On Sat, Nov 10, 2012 at 8:49 PM, Denis Labaye <denis....@gmail.com> wrote:
> How do you avoid repeating this ? A clojure macro?, IDE support?, ... ?

http://code.google.com/p/clj-nstools/

The nstools library has a tool to help with this.

(ns myproject.base
(:require [clojure.set :as set]
[clojure.java.io :as io]
[...]))

Then elsewhere:

(ns+ myproject.database
(:like myproject.base))

Will allow you to declare common :require clauses in one place. Seems
like a pretty elegant design as long as there's no ambiguity as to
what a given alias points to.

-Phil

Mark Engelberg

unread,
Nov 11, 2012, 9:40:05 PM11/11/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 5:59 PM, Sean Corfield <seanco...@gmail.com> wrote:
Denis, Mark, could you speak to what sort of things you're using these
for that make it convenient to have them in every namespace?


set, string, numeric-tower, combinatorics all provide fundamental operations I need throughout my code.
Also, within my project, I have a couple key files that provide constructors and basic conversions between representations for key data types.  These need to be included in nearly every file.

Of course, I also have file of my favorite utilities that I use all the time, including cgrand's improved cond.  Replacing Clojure's cond with that cond means I also have to include a line in my namespace header to exclude core's cond.

My work doesn't usually involve creating a standalone compiled program.  I move around from namespace to namespace, interacting with my code from the REPL.  In a sense, my code along with the REPL is just my "workbench", a suite of utilities that I use to solve problems interactively.  Each file/namespace represents the additional code needed to solve a specific problem, but stands on what I have done before.

This usage means that it makes a lot of sense for me to have access to REPL facilities from most namespaces.

Similarly, I like to save the results of my problem solving session in a database.  That means that within many namespaces, I need to have access to mongodb as well as my files which handle the way that my data structures are packed/unpacked into something storable in the database. 

One complication that hasn't yet been discussed in this conversation about preferring refer to use is that some libraries, such as Incanter, spread functions across several namespaces but the tutorials don't really tell you which functions come from which namespaces.  The tutorial expects you to just "use" all of the relevant namespaces to use Incanter.  Referring all the namespaces would complicate the use of this library considerably (unless you could assign the same alias to several different namespaces, can you do that?).  For every function, you'd need to know which of Incanter's namespaces the function comes from; the division of Incanter functions into separate namespaces is not entirely obvious, that is a hard thing to remember.

Just curious, why do you take such care to go through and remove any redundant imports?  Ultimately, all the same namespaces are going to have to be loaded by Clojure, either directly or indirectly if they are used anywhere in your project.  So you don't really save on load time, or the quantity of things that need to get loaded into memory.  If you consistently use the same aliases across files, there's not really much downside to including them liberally -- doing so basically gives you your own preferred "batteries included" version of Clojure. 

Sean Corfield

unread,
Nov 11, 2012, 10:44:44 PM11/11/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 6:40 PM, Mark Engelberg
<mark.en...@gmail.com> wrote:
> set, string, numeric-tower, combinatorics all provide fundamental operations
> I need throughout my code.

Ah, very different fields of work. Makes sense.

> My work doesn't usually involve creating a standalone compiled program. I
> move around from namespace to namespace, interacting with my code from the
> REPL. In a sense, my code along with the REPL is just my "workbench", a
> suite of utilities that I use to solve problems interactively.

OK. That also makes sense.

> One complication that hasn't yet been discussed in this conversation about
> preferring refer to use is that some libraries, such as Incanter, spread
> functions across several namespaces but the tutorials don't really tell you
> which functions come from which namespaces. The tutorial expects you to
> just "use" all of the relevant namespaces to use Incanter.

Could I argue poor library design here? No well-defined API? :)

> Just curious, why do you take such care to go through and remove any
> redundant imports?

Clarity of intent. When I read an (ns ..) form, it should tell me
exactly what this namespace depends on, no more, no less. I like a
very structured flow of dependencies. When I see repeated dependencies
across namespaces, if feels like a code smell to me and I'll look for
an appropriate refactoring. Sure, some of the "core" Clojure libraries
(core + contrib) are repeated as dependencies in several namespaces,
but even there you might be surprised at how little repetition I have.
Call it OCD :)

Denis Labaye

unread,
Nov 12, 2012, 1:31:56 AM11/12/12
to clo...@googlegroups.com
On Mon, Nov 12, 2012 at 2:59 AM, Sean Corfield <seanco...@gmail.com> wrote:
On Sun, Nov 11, 2012 at 2:26 PM, Mark Engelberg
<mark.en...@gmail.com> wrote:
> I can relate to Denis' issue.  I find it pretty common to have a common set
> of dependencies across every file in a project.

Well, I have to say I was puzzled by Denis' post because I definitely
don't have common dependencies across every file. Now hearing you say
the same thing I'm doubly puzzled...

I don't like to have anything imported that I'm not explicitly using
(and I regularly double-check after refactoring to make sure I remove
any redundant imports). Preferences aside, however, I'm genuinely
curious as to the sort of program structure that has the same
dependencies in every namespace. I can see how some of Denis' imports
are useful for the repl - but I tend to just import them as needed or
write them out in full (clojure.pprint/pprint is my most common one) -
but I'm a bit surprised to see set, string, xml, sh and io all being
that common (in every file).

Denis, Mark, could you speak to what sort of things you're using these
for that make it convenient to have them in every namespace?

I tend to have I/O isolated to one or two namespaces, the same goes
for shell operations, and XML operations. Maybe we're working in
different enough fields that our use cases are very different (I
suspect that's true for Mark - not sure what area Denis works in?).

Sean, 

Most of my Clojure usage is as a scripting language (where other would use Python or Ruby).
I usually don't plan in advance how my program will be splitted in namespaces :
I start from one namespace that does everything, let it grow, and split it if it make sense.

Denis


 
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

Sean Corfield

unread,
Nov 12, 2012, 12:37:27 PM11/12/12
to clo...@googlegroups.com
On Sun, Nov 11, 2012 at 10:31 PM, Denis Labaye <denis....@gmail.com> wrote:
> Most of my Clojure usage is as a scripting language (where other would use
> Python or Ruby).
> I usually don't plan in advance how my program will be splitted in
> namespaces :
> I start from one namespace that does everything, let it grow, and split it
> if it make sense.

Ah, then your use of boilerplate makes sense.

Don't you find the startup time of the JVM to be a disadvantage for
using Clojure vs Python / Ruby?

Denis Labaye

unread,
Nov 17, 2012, 7:37:59 AM11/17/12
to clo...@googlegroups.com
On Mon, Nov 12, 2012 at 6:37 PM, Sean Corfield <seanco...@gmail.com> wrote:
On Sun, Nov 11, 2012 at 10:31 PM, Denis Labaye <denis....@gmail.com> wrote:
> Most of my Clojure usage is as a scripting language (where other would use
> Python or Ruby).
> I usually don't plan in advance how my program will be splitted in
> namespaces :
> I start from one namespace that does everything, let it grow, and split it
> if it make sense.

Ah, then your use of boilerplate makes sense.

Don't you find the startup time of the JVM to be a disadvantage for
using Clojure vs Python / Ruby?

.... or even Bash :)

Yes the JVM startup time makes using the JVM impractical for "little scripts".
I always have my Clojure "juggernaut project" open all the time , it's a project with all the dependencies I am using, so when I need to use or write some new Clojure code I don't have the penality of the JVM startup.

This is definitively not ideal, but it's working. May be improved with projects that preload a JVM in advance (like Drip), or by using a client - server model (exposing my "juggernaut project" as a REST API), to be able to invoke it from the command line (curl, ...).
Or just waiting for project Jigsaw in Java 8 (or 9, or 10, ...?)
 
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
World Singles, LLC. -- http://worldsingles.com/

"Perfection is the enemy of the good."
-- Gustave Flaubert, French realist novelist (1821-1880)

Reply all
Reply to author
Forward
0 new messages