clojure.lib coding standards: initial draft brain dump

117 views
Skip to first unread message

Stuart Halloway

unread,
Feb 2, 2010, 8:30:22 AM2/2/10
to cloju...@googlegroups.com
CLOJURE.LIB CODING STANDARDS

Disclaimers and Random Observations:

* This is not an official or final list -- intended as provocation for
discussion. If some of them aren't dead wrong then I didn't try hard
enough. :-)

* Rules are made to be broken, so whatever standards we come up with
will not be absolute.

* Putting my money where my mouth is: I am willing to dedicate
significant time to editing existing code to be in line with the
standards, once we agree on some.

* This document should (eventually) be useful for programmers
fairly new to Clojure. Links out to additional exposition is
probably the way to go.

The Standards:

* Get the name and signature right. Rich strongly respects Java's
commitment to not break existing code. In practice, that means we
can tweak the implementation forever, but once we publish a name
and signature we need to stick with it. (In practice I think this
means that we want many people to review the name and sig, even if
they don't review the implementation details.)

* Use type hints where appropriate - *warn-on-reflection* should not
bark at lib code.

* Use good names, and don't be afraid to collide with names in other
namespaces. That's what the flexible namespace support is there for.

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

* Don't use a macro when a function can do the job. If a macro is
important for ease-of-use, expose the function version as
well. (Open question: should there be a naming convention here? A
lot of places use "foo" and "foo*".)

* If you are sure you have all the information at compile time, use a
macro where it would improve performance sensitive code. (The
discussion on a macro for logging [2] is instructive. We end up
needing both versions because the information is only *sometimes*
available at compile time.)

* Provide a library-level docstring.

* Provide automated tests with full branch coverage.

* Unroll optional arguments. That is
(foo x y :optional z)
not
(foo x y {:optional z})
--This one is from Rich.

* Use '?' suffix for predicates.

* Include a docstring. Except: If your function is so self-explanatory
that the docstring cannot do anything more than repeat the name and
arglist, then do not include a docstring. (Personally I would remove
some of the docstrings already in place.)

* When in doubt, expose the performant version. Clojure goes to great
lengths to enable performance when you need it, and lib should
too. (That's why we don't have multimethod + in core, for instance.)
Users can always create more polymorphic APIs on their own,
hijacking symbols if they want to.

* If you take a good name that collides with core, make sure your
semantics are parallel (possibly minus laziness). Good example of
this is string functions that shadow core seq functions.

* Make liberal use of assert and pre- and post- conditions. This is
not idiomatic today, but it should be going forward. See [1].

* Be lazy where possible.

* Follow clojure.core's example for idiomatic names like pred and
coll.

* Do NOT follow idioms from clojure.core's preamble code. That code
runs in a limited environment because Clojure is not bootstrapped
yet.

* Decompose the pieces. If your name isn't Rich, don't write a form as
long as, say, the definition of doseq.

* Use (:property foo) to access objects, but (foo :property) to reach
into collections. The difference communicates what you think foo is.

* Idiomatic code uses destructuring a lot. However, you should only
destructure in the arg list if you want to communicate the
substructure as part of the caller contract. Otherwise, destructure
in a first-line let. Example: my snake code from the book [3] fails
this test, doing too much destructuring in arg lists.

* Prefer updating over setting. Many reasons: the unified update model
provides a simple standard way to do this. Helps you discover
commutative operations. Reduces the surface area of assumptions you
are making about the object you are updating.

* Don't support operations on the wrong collection type. If your
algorithm is only performant with random access, then require an
arg that has random access.

* Use *earmuffs* only for things intended for rebinding.

* Use the bang! only for things not safe in an STM transaction.

* Prefer sequence-library composition over explicit loop/recur.

* Rebindable vars should be paired with scoping macros, e.g. *in* and
with-in-str.

* Lazy seqs should be exposed as functions that hold only the minimum
state needed, a.k.a. "let go of your head." Let the caller decide
how much local memory they want to use.

[1] http://www.assembla.com/spaces/clojure/tickets/250-turn-off-able-asserts--with-better-messages
[2] http://groups.google.com/group/clojure/browse_thread/thread/79c609df3632a5d1/40fbbacf3b2cc1e5?lnk=gst&q=log4j+not+detected#40fbbacf3b2cc1e5
[3] http://github.com/stuarthalloway/programming-clojure/commit/7758eac3b0434654902835fde47c854708538864

Sean Devlin

unread,
Feb 2, 2010, 8:55:31 AM2/2/10
to cloju...@googlegroups.com
One addition:

* Data goes last, when possible (e.g. the str-utils3 migration).  Design around ->>, comp & partial.  Designing around -> is a last resort.

One Contradiction:

* DO support operations on the wrong collection type (e.g. random access).  Indicate any constraints in the doc, but let me worry about that as a consumer of the lib.

One Personal Request:

Give me enough test cases, doc strings, and a use case or two, so I can create an episode for each namespace.  Beginner education & all that.


--
You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
To post to this group, send email to cloju...@googlegroups.com.
To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/clojure-dev?hl=en.


Laurent PETIT

unread,
Feb 2, 2010, 9:27:35 AM2/2/10
to cloju...@googlegroups.com
Hello,

2010/2/2 Sean Devlin <francoi...@gmail.com>:


> One addition:
>
> * Data goes last, when possible (e.g. the str-utils3 migration).

Not sure about that one. e.g. with prototypes data goes first.

> Design
> around ->>, comp & partial.  Designing around -> is a last resort.

Not sure about that one. While I understand your appeal to point-free
style, I would not make this a general rule.

The general rule would better be expressed as : prefer code clarity
over compactness.

Chouser

unread,
Feb 2, 2010, 9:29:42 AM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 8:30 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
> CLOJURE.LIB CODING STANDARDS
>
[snip]

>
> * Use type hints where appropriate - *warn-on-reflection* should not
>  bark at lib code.

Strike one! :-)

For example, someone mentioned that repl-utils generates a lot of
reflection warnings, but the stuff defined there is never
intended to be used in critical paths. It seems to me type hints
sufficient to prevent warnings there would actually be an
anti-pattern, a demonstration of unnecessary over-hinting in code
that doesn't need it -- not something to be recommended to people
new to Clojure.

Perhaps we need a way to turn off reflection warnings on
a per-namespace basis or something? Or maybe just have 'load'
do:

(binding [*warn-on-reflection* *warn-on-reflection*] ...)

...so that it's safe to set it on and off as needed in .clj code
files?

> * Provide automated tests with full branch coverage.

Are we leaving behind the headstrong care-free days of our youth?

> * Follow clojure.core's example for idiomatic names like pred and
>  coll.

You're referring to argument names here?

I like all the rest. Perhaps add:

* Use (Klass/static) (Klass.) and (.instance obj) interop styles,
with the only exception being in code-generating-code where the
older (. blah) style may be easier to produce.

It may not be necessary for contrib commiters, but I still see
a startling amount of new code in the wild that violates that
rule, so it may be worth mentioning explicitly.

Thanks for pulling this together.
--Chouser

Chas Emerick

unread,
Feb 2, 2010, 9:31:36 AM2/2/10
to cloju...@googlegroups.com

On Feb 2, 2010, at 8:30 AM, Stuart Halloway wrote:

> * Use type hints where appropriate - *warn-on-reflection* should not
> bark at lib code.

IMO, this collides with the recent moved towards not AOT-compiling
contrib -- if that doesn't happen regularly, then no one's going to
notice reflection warnings.

> * Unroll optional arguments. That is
> (foo x y :optional z)
> not
> (foo x y {:optional z})
> --This one is from Rich.

Could you clarify this, or point to an example? I'm not grokking at
the moment.

> * Make liberal use of assert and pre- and post- conditions. This is
> not idiomatic today, but it should be going forward. See [1].

I'd +1 this, with the caveat that preconditions should not be used for
verifying arguments to 'public' functions (since those assertions'
execution is at the behest/permission of whoever's running the code).
I'll refer here to the relevant Java-specific guidelines on assertions
in conjunction with public APIs: http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html

> * Use (:property foo) to access objects, but (foo :property) to reach
> into collections. The difference communicates what you think foo is.

I'd disagree here -- I always use (:property foo), whether foo is a
map or an object. IMO, (foo :property) should only be used to invoke
a defined fn foo.

> * Use *earmuffs* only for things intended for rebinding.

And I'd add use plus signs for things that are decidedly constant and
not intended to be rebound, like +speed-of-light+.

Cheers,

- Chas

Laurent PETIT

unread,
Feb 2, 2010, 9:53:21 AM2/2/10
to cloju...@googlegroups.com
2010/2/2 Chas Emerick <ceme...@snowtide.com>:

>
> On Feb 2, 2010, at 8:30 AM, Stuart Halloway wrote:
>
>> * Use type hints where appropriate - *warn-on-reflection* should not
>>  bark at lib code.
>
> IMO, this collides with the recent moved towards not AOT-compiling contrib
> -- if that doesn't happen regularly, then no one's going to notice
> reflection warnings.
>
>> * Unroll optional arguments. That is
>>  (foo x y :optional z)
>>  not
>>  (foo x y {:optional z})
>>  --This one is from Rich.
>
> Could you clarify this, or point to an example?  I'm not grokking at the
> moment.
>
>> * Make liberal use of assert and pre- and post- conditions. This is
>>  not idiomatic today, but it should be going forward. See [1].
>
> I'd +1 this, with the caveat that preconditions should not be used for
> verifying arguments to 'public' functions (since those assertions' execution
> is at the behest/permission of whoever's running the code).  I'll refer here
> to the relevant Java-specific guidelines on assertions in conjunction with
> public APIs: http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html

Nope. It depends on what has been explicitly specified in the
"documentation part" of the public method : in the examples shown in
the above mentioned link, the method javadoc explictly states it will
(throw an exception if arg1 ...). But that's not preconditions for me,
that's "belt and strap" (is this an idomatic english expression ?). A
precondition would just be : "we expect the arg to respect conditions
x & y, ..., otherwise, undefined behaviour".
So I don't see why one could not check args in preconditions,
depending on how one has formulated it in the docstring.

>
>> * Use (:property foo) to access objects, but (foo :property) to reach
>>  into collections. The difference communicates what you think foo is.
>
> I'd disagree here -- I always use (:property foo), whether foo is a map or
> an object.  IMO, (foo :property) should only be used to invoke a defined fn
> foo.
>
>> * Use *earmuffs* only for things intended for rebinding.
>
> And I'd add use plus signs for things that are decidedly constant and not
> intended to be rebound, like +speed-of-light+.
>
> Cheers,
>
> - Chas
>

Constantine Vetoshev

unread,
Feb 2, 2010, 10:31:05 AM2/2/10
to Clojure Dev
On Feb 2, 8:30 am, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> * Unroll optional arguments. That is
>    (foo x y :optional z)
>    not
>    (foo x y {:optional z})
>    --This one is from Rich.

I'll take this golden opportunity to bring up let-kw again. :) It
makes this style of keyword argument parsing easy. Except now I think
it belongs somewhere other than c.c.macros.
http://www.assembla.com/spaces/clojure-contrib/tickets/51

Laurent PETIT

unread,
Feb 2, 2010, 10:37:07 AM2/2/10
to cloju...@googlegroups.com
2010/2/2 Constantine Vetoshev <gepa...@gmail.com>:

inc

I guess one namespace could be just named c.c.lib, or c.c.core (in
this case, all existing stuff in c.c.core that is not yet relevant for
c.c.lib could be move somewhere else), and "hold" all utility
functions / macros that complement clojure.core.
Those utility functions/macros that are of very general utility and
currently scattered throughout c.c (or placed in namespaces which
technical names e.g. c.c.macros) could be migrated to c.c.core.

Stuart Halloway

unread,
Feb 2, 2010, 1:46:30 PM2/2/10
to cloju...@googlegroups.com
I like let-kw, but there is another possibility too: Rich is
considering adding a special destructuring syntax for keyword args.

Stu

Richard Newman

unread,
Feb 2, 2010, 1:52:24 PM2/2/10
to cloju...@googlegroups.com
> I'd disagree here -- I always use (:property foo), whether foo is a
> map or an object. IMO, (foo :property) should only be used to
> invoke a defined fn foo.

Hell yes. I only use (foo :property) when I'm really, really excited
about the possibility of a NullPointerException.

"The thing that isn't null" goes at the front.

Stuart Halloway

unread,
Feb 2, 2010, 1:53:56 PM2/2/10
to cloju...@googlegroups.com
> One addition:
>
> * Data goes last, when possible (e.g. the str-utils3 migration).
> Design around ->>, comp & partial. Designing around -> is a last
> resort.

I would change this to "think carefully about arg order, and be
consistent within a lib."

> One Contradiction:
>
> * DO support operations on the wrong collection type (e.g. random
> access). Indicate any constraints in the doc, but let me worry
> about that as a consumer of the lib.

Still not sold. Other votes.

> One Personal Request:
>
> Give me enough test cases, doc strings, and a use case or two, so I
> can create an episode for each namespace. Beginner education & all
> that.

Agreed.

Stu

Stuart Halloway

unread,
Feb 2, 2010, 1:57:07 PM2/2/10
to cloju...@googlegroups.com
Stu:

>> * Use type hints where appropriate - *warn-on-reflection* should not
>> bark at lib code.

Chouser:

> Strike one! :-)
>
> For example, someone mentioned that repl-utils generates a lot of
> reflection warnings, but the stuff defined there is never
> intended to be used in critical paths. It seems to me type hints
> sufficient to prevent warnings there would actually be an
> anti-pattern, a demonstration of unnecessary over-hinting in code
> that doesn't need it -- not something to be recommended to people
> new to Clojure.
>
> Perhaps we need a way to turn off reflection warnings on
> a per-namespace basis or something? Or maybe just have 'load'
> do:
>
> (binding [*warn-on-reflection* *warn-on-reflection*] ...)
>
> ...so that it's safe to set it on and off as needed in .clj code
> files?

Other thoughts?

-Stu

Stuart Halloway

unread,
Feb 2, 2010, 1:58:23 PM2/2/10
to cloju...@googlegroups.com
>> * Provide automated tests with full branch coverage.
>
> Are we leaving behind the headstrong care-free days of our youth?

Yes. This is for lib, not contrib. I think there should be a higher
bar (and I am willing to write the tests myself.)

> * Use (Klass/static) (Klass.) and (.instance obj) interop styles,
> with the only exception being in code-generating-code where the
> older (. blah) style may be easier to produce.

Good one. Added.

Stu

Sean Devlin

unread,
Feb 2, 2010, 1:59:16 PM2/2/10
to cloju...@googlegroups.com
(inc chouser)

Stuart Halloway

unread,
Feb 2, 2010, 2:01:29 PM2/2/10
to cloju...@googlegroups.com, Rich Hickey
Rich, can you weigh in on this one?

Stu

* Use (:property foo) to access objects, but (foo :property) to reach
into collections. The difference communicates what you think foo is.

>> I'd disagree here -- I always use (:property foo), whether foo is a

Stuart Halloway

unread,
Feb 2, 2010, 2:03:24 PM2/2/10
to cloju...@googlegroups.com
I am changing the wording to "use type hints where lib code is likely
to be on a critical code path."

Stu

P.S. Two chousers sounds like a good idea to me too.

Stuart Halloway

unread,
Feb 2, 2010, 2:08:33 PM2/2/10
to cloju...@googlegroups.com
> And I'd add use plus signs for things that are decidedly constant
> and not intended to be rebound, like +speed-of-light+.
>
> Cheers,
>
> - Chas

I know such names are idiomatic in some lisps, but haven't seen them
very often in Clojure. Other votes yay or nay?

Stu

Stuart Halloway

unread,
Feb 2, 2010, 2:12:16 PM2/2/10
to cloju...@googlegroups.com
>> * Unroll optional arguments. That is
>> (foo x y :optional z)
>> not
>> (foo x y {:optional z})
>> --This one is from Rich.
>
> Could you clarify this, or point to an example? I'm not grokking at
> the moment.

Rewritten to:

* Unroll optional named arguments. Callers should not have to wrap
optional named arguments in a map literal:

(release-sharks 2 :laser-beams true) ; good
(release-sharks 2 {:laser-beams true}) ; bad

Sean Devlin

unread,
Feb 2, 2010, 2:20:29 PM2/2/10
to cloju...@googlegroups.com
This is a bad example, it should be +speed-of-light-in-vacuum+, but anyway...

The only use I've ever had for this is pi, and it's so central I keep it that short.  I've never used the pluses.

Sean

Chas Emerick

unread,
Feb 2, 2010, 2:20:41 PM2/2/10
to cloju...@googlegroups.com

Oh, OK. I read 'unroll', started thinking about loops, and lost it
from there.

My opinion on this is completely tied to whatever the plan is for
supporting kw args in the language.

- Chas

Chouser

unread,
Feb 2, 2010, 2:23:33 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 2:08 PM, Stuart Halloway
<stuart....@gmail.com> wrote:

nay

By far the most common Vars to be constant and not intended
to be rebound are bound to functions, and are named without
decoration. I don't see any need to for non-fns or IFns like
maps and vectors to be any different. If they're not bound
thread-locally, their definitions should be as stable and
discoverable as locals and function Vars -- if not in the direct
lexical scope, then named earlier in the file either where
they're defined or named in a :use :only list.

--Chouser

Chas Emerick

unread,
Feb 2, 2010, 2:28:08 PM2/2/10
to cloju...@googlegroups.com
Indeed, it was a bad example, especially insofar as I implied that it's somehow meant only for mathematical things.  Other examples:

(def +couchdb-url+ (System/getProperty ...))

(def +node-start-time+ (System/currentTimeMillis))

The point is to make it super-obvious that a particular var is not meant to be rebound.

- Chas

Dimitry Gashinsky

unread,
Feb 2, 2010, 2:29:24 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 2:01 PM, Stuart Halloway
<stuart....@gmail.com> wrote:
> * Use (:property foo) to access objects, but (foo :property) to reach
>  into collections. The difference communicates what you think foo is.
>
>>> I'd disagree here -- I always use (:property foo), whether foo is a map
>>> or an object.  IMO, (foo :property) should only be used to invoke a defined
>>> fn foo.
>>
>> Hell yes. I only use (foo :property) when I'm really, really excited about
>> the possibility of a NullPointerException.

I start using somewhat redundant (-> foo :property) for some of the
code if I really want to indicate foo as an object, also prevents NPE.

DiG

Chouser

unread,
Feb 2, 2010, 2:41:28 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 2:01 PM, Stuart Halloway
<stuart....@gmail.com> wrote:

I wonder if part of the disagreement depends on whether the map
key is a literal keyword or not. Rarely do I say (foo :prop)
with a literal keyword like that, but then usually if I know the
key name in the code like that it's because foo is acting as an
object not a collection.

However, (coll some-key) is not uncommon for me, and it then
often depends whether I think coll or some-key is more likely to
be nil, or whether there's any chance some-key may not be
a keyword or symbol. ...though now that I think about it
(some-key coll) seems really weird even if there's a chance coll
will be nil. I'm more likely to say (get coll some-key) which
allows nils on either.

--Chouser

Laurent PETIT

unread,
Feb 2, 2010, 2:43:58 PM2/2/10
to cloju...@googlegroups.com
2010/2/2 Stuart Halloway <stuart....@gmail.com>:

> I am changing the wording to "use type hints where lib code is likely to be
> on a critical code path."
>
> Stu
>
> P.S. Two chousers sounds like a good idea to me too.
>
>> (inc chouser)

Please, (swap! chouser inc) ! Chouser is not just a value, but an identity :-)

Richard Newman

unread,
Feb 2, 2010, 2:46:31 PM2/2/10
to cloju...@googlegroups.com
> I wonder if
...
> However ... not uncommon ... depends ... more likely
...

> ...though now that I think about it
...

> I'm more likely to say
...

It's almost like this is something that can't easily be boiled down to
one line in a style guide ;)

All I think needs to be mandated is that code avoids NPEs in edge
cases. That's the functional requirement.

That might mean using get, or keyword-first, or an explicit guard.
Beyond that it's something that an educated programmer can decide for
themselves.

Laurent PETIT

unread,
Feb 2, 2010, 2:48:14 PM2/2/10
to cloju...@googlegroups.com
2010/2/2 Chas Emerick <ceme...@snowtide.com>:

> Indeed, it was a bad example, especially insofar as I implied that it's
> somehow meant only for mathematical things.  Other examples:
> (def +couchdb-url+ (System/getProperty ...))
> (def +node-start-time+ (System/currentTimeMillis))
> The point is to make it super-obvious that a particular var is not meant to
> be rebound.

I'm wondering if this is important at the point where it is defined,
or when it is used ?
If the former, then maybe creating an alias from def to defconstant
could convey the meaning (and also open the door for defconstant
really doing something later on) ?

> - Chas
> On Feb 2, 2010, at 2:20 PM, Sean Devlin wrote:
>
> This is a bad example, it should be +speed-of-light-in-vacuum+, but
> anyway...
>
> The only use I've ever had for this is pi, and it's so central I keep it
> that short.  I've never used the pluses.
>
> Sean
>
> On Tue, Feb 2, 2010 at 2:08 PM, Stuart Halloway <stuart....@gmail.com>
> wrote:
>>>
>>> And I'd add use plus signs for things that are decidedly constant and not
>>> intended to be rebound, like +speed-of-light+.
>>>
>>> Cheers,
>>>
>>> - Chas
>>
>> I know such names are idiomatic in some lisps, but haven't seen them very
>> often in Clojure. Other votes yay or nay?
>>
>> Stu
>

Sean Devlin

unread,
Feb 2, 2010, 2:49:03 PM2/2/10
to cloju...@googlegroups.com
Well, in that case...

(send chouser inc)

People = Agents in my mind :)

Sean Devlin

unread,
Feb 2, 2010, 2:50:10 PM2/2/10
to cloju...@googlegroups.com
Like add standard metadata?

e.g.

{:symbolic-value true}

Chouser

unread,
Feb 2, 2010, 3:02:06 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 2:46 PM, Richard Newman <holy...@gmail.com> wrote:
>> I wonder if
>
> ...
>>
>> However ... not uncommon ... depends ... more likely
>
> ...
>>
>> ...though now that I think about it
>
> ...
>>
>> I'm more likely to say
>
> ...
>
> It's almost like this is something that can't easily be boiled down to one
> line in a style guide ;)

Well, just because *my* thinking is fuzzy doesn't mean the style
guide needs to be.

--Chouser

Rich Hickey

unread,
Feb 2, 2010, 3:21:38 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 8:55 AM, Sean Devlin <francoi...@gmail.com> wrote:
> One addition:
>
> * Data goes last, when possible (e.g. the str-utils3 migration).  Design
> around ->>, comp & partial.  Designing around -> is a last resort.
>

Definitely not. Everyone please see:

http://groups.google.com/group/clojure/browse_frm/thread/8b2c8dc96b39ddd7

for a more nuanced description of what is going on in Clojure.

> One Contradiction:
>
> * DO support operations on the wrong collection type (e.g. random access).
> Indicate any constraints in the doc, but let me worry about that as a
> consumer of the lib.
>

Also, no. In almost every case, I've regretted the few times I've let
a function apply to non-matching collection types. This is a recipe
for "Lisp is slow". People write their CL apps using assoc lists and
linear time list functions and they die when the n-squared nested perf
hits them on larger data. Functions map to abstractions and the
abstractions are supported where efficient. That is the Clojure way.

> One Personal Request:
>
> Give me enough test cases, doc strings, and a use case or two, so I can
> create an episode for each namespace.  Beginner education & all that.
>

The question with this is - where does it go? Should a library jar be
bloated with example code?

Rich

Rich Hickey

unread,
Feb 2, 2010, 3:27:36 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 9:31 AM, Chas Emerick <ceme...@snowtide.com> wrote:

>
> On Feb 2, 2010, at 8:30 AM, Stuart Halloway wrote:
>
>> * Use (:property foo) to access objects, but (foo :property) to reach
>>  into collections. The difference communicates what you think foo is.
>
> I'd disagree here -- I always use (:property foo), whether foo is a map or
> an object.  IMO, (foo :property) should only be used to invoke a defined fn
> foo.
>

The original is my recommendation, although the names in the example
are bad - these are better:

(:property object-like-map)

(collection-like-map key) ;or, use get

Rich

Rich Hickey

unread,
Feb 2, 2010, 3:30:37 PM2/2/10
to cloju...@googlegroups.com

Please, no. Few libraries should be designed to accept nil where a map
is required, and if you are doing that, use 'get'. The maps-as-objects
vs maps-as-collections dichotomy is useful.

Rich

Sean Devlin

unread,
Feb 2, 2010, 3:32:01 PM2/2/10
to cloju...@googlegroups.com

Maybe each official ns gets a page on Clojure.org?  It'd keep the .jar thin, and it's place for official docs to go.
 

Kevin Downey

unread,
Feb 2, 2010, 3:31:56 PM2/2/10
to cloju...@googlegroups.com
I think promoting the use of the io! macro around stuff that cannot go
inside a transaction would be a good idea

On Tue, Feb 2, 2010 at 5:30 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
> CLOJURE.LIB CODING STANDARDS
>
> Disclaimers and Random Observations:
>
> * This is not an official or final list -- intended as provocation for
>  discussion. If some of them aren't dead wrong then I didn't try hard
>  enough. :-)
>
> * Rules are made to be broken, so whatever standards we come up with
>  will not be absolute.
>
> * Putting my money where my mouth is: I am willing to dedicate
>  significant time to editing existing code to be in line with the
>  standards, once we agree on some.
>
> * This document should (eventually) be useful for programmers
>  fairly new to Clojure. Links out to additional exposition is
>  probably the way to go.
>
> The Standards:
>
> * Get the name and signature right. Rich strongly respects Java's
>  commitment to not break existing code. In practice, that means we
>  can tweak the implementation forever, but once we publish a name
>  and signature we need to stick with it. (In practice I think this
>  means that we want many people to review the name and sig, even if
>  they don't review the implementation details.)


>
> * Use type hints where appropriate - *warn-on-reflection* should not
>  bark at lib code.
>

> * Use good names, and don't be afraid to collide with names in other
>  namespaces. That's what the flexible namespace support is there for.
>
> * Be explicit and minimalist about dependencies on other
>  packages. (Prefer the :only option to use and require).
>
> * Don't use a macro when a function can do the job. If a macro is
>  important for ease-of-use, expose the function version as
>  well. (Open question: should there be a naming convention here? A
>  lot of places use "foo" and "foo*".)
>
> * If you are sure you have all the information at compile time, use a
>  macro where it would improve performance sensitive code. (The
>  discussion on a macro for logging [2] is instructive. We end up
>  needing both versions because the information is only *sometimes*
>  available at compile time.)
>
> * Provide a library-level docstring.


>
> * Provide automated tests with full branch coverage.
>

> * Unroll optional arguments. That is
>  (foo x y :optional z)
>  not
>  (foo x y {:optional z})
>  --This one is from Rich.
>

> * Use '?' suffix for predicates.
>
> * Include a docstring. Except: If your function is so self-explanatory
>  that the docstring cannot do anything more than repeat the name and
>  arglist, then do not include a docstring. (Personally I would remove
>  some of the docstrings already in place.)
>
> * When in doubt, expose the performant version. Clojure goes to great
>  lengths to enable performance when you need it, and lib should
>  too. (That's why we don't have multimethod + in core, for instance.)
>  Users can always create more polymorphic APIs on their own,
>  hijacking symbols if they want to.
>
> * If you take a good name that collides with core, make sure your
>  semantics are parallel (possibly minus laziness). Good example of
>  this is string functions that shadow core seq functions.
>
> * Make liberal use of assert and pre- and post- conditions. This is
>  not idiomatic today, but it should be going forward. See [1].
>
> * Be lazy where possible.
>
> * Follow clojure.core's example for idiomatic names like pred and
>  coll.
>
> * Do NOT follow idioms from clojure.core's preamble code. That code
>  runs in a limited environment because Clojure is not bootstrapped
>  yet.
>
> * Decompose the pieces. If your name isn't Rich, don't write a form as
>  long as, say, the definition of doseq.


>
> * Use (:property foo) to access objects, but (foo :property) to reach
>  into collections. The difference communicates what you think foo is.
>

> * Idiomatic code uses destructuring a lot. However, you should only
>  destructure in the arg list if you want to communicate the
>  substructure as part of the caller contract. Otherwise, destructure
>  in a first-line let. Example: my snake code from the book [3] fails
>  this test, doing too much destructuring in arg lists.
>
> * Prefer updating over setting. Many reasons: the unified update model
>  provides a simple standard way to do this. Helps you discover
>  commutative operations. Reduces the surface area of assumptions you
>  are making about the object you are updating.
>
> * Don't support operations on the wrong collection type. If your
>  algorithm is only performant with random access, then require an
>  arg that has random access.
>
> * Use *earmuffs* only for things intended for rebinding.
>
> * Use the bang! only for things not safe in an STM transaction.
>
> * Prefer sequence-library composition over explicit loop/recur.
>
> * Rebindable vars should be paired with scoping macros, e.g. *in* and
>  with-in-str.
>
> * Lazy seqs should be exposed as functions that hold only the minimum
>  state needed, a.k.a. "let go of your head." Let the caller decide
>  how much local memory they want to use.
>
> [1]
> http://www.assembla.com/spaces/clojure/tickets/250-turn-off-able-asserts--with-better-messages
> [2]
> http://groups.google.com/group/clojure/browse_thread/thread/79c609df3632a5d1/40fbbacf3b2cc1e5?lnk=gst&q=log4j+not+detected#40fbbacf3b2cc1e5
> [3]
> http://github.com/stuarthalloway/programming-clojure/commit/7758eac3b0434654902835fde47c854708538864


>
> --
> You received this message because you are subscribed to the Google Groups
> "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to
> clojure-dev...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/clojure-dev?hl=en.
>
>

--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Rich Hickey

unread,
Feb 2, 2010, 3:54:36 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 3:31 PM, Kevin Downey <red...@gmail.com> wrote:
> I think promoting the use of the io! macro around stuff that cannot go
> inside a transaction would be a good idea
>

Ideally, the libs should utilize the (unfinished) resource management
'scopes'. Perhaps getting those done is a prerequisite for I/O libs.

Rich

Meikel Brandmeyer

unread,
Feb 2, 2010, 3:57:26 PM2/2/10
to cloju...@googlegroups.com
Am 02.02.2010 um 21:31 schrieb Kevin Downey:

> I think promoting the use of the io! macro around stuff that cannot go
> inside a transaction would be a good idea

+1

Richard Newman

unread,
Feb 2, 2010, 3:36:56 PM2/2/10
to cloju...@googlegroups.com
> Please, no. Few libraries should be designed to accept nil where a map
> is required, and if you are doing that, use 'get'.

Most of mine do so -- for example, where I'm pulling some JSON from a
remote service or a scraper, and any sequence or map could be empty or
missing. I don't see any advantage to using get without a default.

> The maps-as-objects vs maps-as-collections dichotomy is useful.

If this is currently paged into your mind, could you spare a few words
to explain why you think it's useful? (Or point me to some old post?)

Rich Hickey

unread,
Feb 2, 2010, 4:55:21 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 3:36 PM, Richard Newman <holy...@gmail.com> wrote:
>> Please, no. Few libraries should be designed to accept nil where a map
>> is required, and if you are doing that, use 'get'.
>
> Most of mine do so -- for example, where I'm pulling some JSON from a remote
> service or a scraper, and any sequence or map could be empty or missing. I
> don't see any advantage to using get without a default.
>

get is nil-collection tolerant and supports any kind of key.

>> The maps-as-objects vs maps-as-collections dichotomy is useful.
>
> If this is currently paged into your mind, could you spare a few words to
> explain why you think it's useful? (Or point me to some old post?)
>

Well, here's the simplest separation:

It's quite rare to have something other than keywords as
field/property/attribute names,

It's quite common to have a variety of things (e.g. strings, numbers)
as keys for collection-like maps, but, of those, only keywords act as
functions. If you build library code that does (key map) it will only
work for keyword keys.

Rich

Stuart Halloway

unread,
Feb 2, 2010, 4:52:12 PM2/2/10
to cloju...@googlegroups.com
I like this. Are there limits? Should pretty much all of the c.c.io
functions get wrapped?

Stu

Richard Newman

unread,
Feb 2, 2010, 5:06:52 PM2/2/10
to cloju...@googlegroups.com
> It's quite common to have a variety of things (e.g. strings, numbers)
> as keys for collection-like maps, but, of those, only keywords act as
> functions. If you build library code that does (key map) it will only
> work for keyword keys.

I see. Yes, that makes sense. I didn't understand your distinction,
because even my "collection-like" maps usually have keyword keys
(e.g., even scraper results typically intern the keys as keywords).

In my code, maps with non-keyword keys usually don't escape the scope
of a function. (That's not a rule, just an observation.)

Perhaps this concrete distinction could be used in a style guideline,
rather than the abstract notion "of object versus collection"? E.g.,

* If you want to have a default value if the key isn't found, use
get.

* If you know that the key you want to retrieve is a keyword, e.g.,
if the keyword is known in advance, then use (:keyword coll).

* If you're accessing keys in a heterogenous or non-keyword-key
collection, or you don't know the key in advance, and
* You know the collection cannot be nil, then
* Use (coll key)
* If the collection could be nil, either
* Use a guard, or
* Use (get coll key).

I think that concretely sums up the situations in which you might use
each approach, no?

Phil Hagelberg

unread,
Feb 2, 2010, 5:39:14 PM2/2/10
to Clojure Dev
On Feb 2, 11:08 am, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> > And I'd add use plus signs for things that are decidedly constant  
> > and not intended to be rebound, like +speed-of-light+.
>
> I know such names are idiomatic in some lisps, but haven't seen them  
> very often in Clojure. Other votes yay or nay?

Definitely opposed to +names-like-this+. Immutability is the default,
why have an extra convention to emphasize it?

-Phil

Chas Emerick

unread,
Feb 2, 2010, 6:44:25 PM2/2/10
to cloju...@googlegroups.com

In my usage, this convention has nothing to do with what value is
bound to the var -- it indicates whether the var itself is intended to
be rebound.

- Chas

Rich Hickey

unread,
Feb 2, 2010, 6:56:27 PM2/2/10
to Clojure Dev
See http://groups.google.com/group/clojure-dev/msg/9a02559f45ca63d2

I don't want to promote heavy use of io! with scopes upcoming.

Fogus

unread,
Feb 2, 2010, 7:53:36 PM2/2/10
to Clojure Dev
> (def +couchdb-url+ (System/getProperty ...))
> (def +node-start-time+ (System/currentTimeMillis))

I could never stand the +blah+ convention so my vote is nay.

Maybe I am being dense, but if you really need a "constant"
representing the speed of light in a vacuum, then what's wrong with
(def C 2.99792458e8)? All-caps for constants has precedent.

-m

Phil Hagelberg

unread,
Feb 2, 2010, 8:06:10 PM2/2/10
to cloju...@googlegroups.com
On Tue, Feb 2, 2010 at 3:44 PM, Chas Emerick <ceme...@snowtide.com> wrote:
>>> I know such names are idiomatic in some lisps, but haven't seen them
>>> very often in Clojure. Other votes yay or nay?
>>
>> Definitely opposed to +names-like-this+. Immutability is the default,
>> why have an extra convention to emphasize it?
>
> In my usage, this convention has nothing to do with what value is bound to
> the var -- it indicates whether the var itself is intended to be rebound.

Vars that are intended to be rebound already have their own convention
too. Intended-not-to-be-rebound is implied by default.

-Phil

Timothy Pratley

unread,
Feb 3, 2010, 2:02:45 AM2/3/10
to cloju...@googlegroups.com
On 3 February 2010 05:57, Stuart Halloway <stuart....@gmail.com> wrote:
> Other thoughts?


You got me wondering, if I did want to write a test that a name-space
contains no reflection... could I do it? Not easily at present.

I'd be happy to put together a patch to record or detect reflection
warnings in a way that can be used for testing if that's considered
useful.

Konrad Hinsen

unread,
Feb 3, 2010, 3:34:54 AM2/3/10
to cloju...@googlegroups.com
On 02.02.2010, at 14:30, Stuart Halloway wrote:

> * Use type hints where appropriate - *warn-on-reflection* should not
> bark at lib code.

Sometimes reflection is inevitable or even the reason for having a
library function, as opposed to calling Java directly.

> * Use good names, and don't be afraid to collide with names in other
> namespaces. That's what the flexible namespace support is there for.

I agree in general, but what about clojure.core? Given the implied
refer-clojure in a plain (ns...), name conflicts with clojure.core are
a bit of a pain to handle.

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

Again, should there be an exception for clojure.core?

> * When in doubt, expose the performant version. Clojure goes to great
> lengths to enable performance when you need it, and lib should
> too. (That's why we don't have multimethod + in core, for instance.)
> Users can always create more polymorphic APIs on their own,
> hijacking symbols if they want to.

Right, but that applies not just to users, also to library authors. A
library may well have the main purpose of providing generic rather
than performant functions. The recommendation should be weakened: Make
a clear distinction between performant and generic versions, and
create separate namespaces for them.

Konrad.

Stuart Halloway

unread,
Feb 3, 2010, 1:51:24 PM2/3/10
to cloju...@googlegroups.com
inc

Jonathan Smith

unread,
Feb 3, 2010, 9:51:32 PM2/3/10
to Clojure Dev
I use this convention all of the time.

*var* is global-mutable
+var+ is a global-constant
Anything lexically bound (in a let) is 'normal'.

Why do I do this?

I want to differentiate between globals and lexicals.

If I'm reading code (after I have long forgotten what it was the code
was doing),
I don't want to have to look up 'is this a variable i just bound, or
is this a global-constant'.

(A lot of the time it isn't as obvious as speed-of-light-inside-a-
vacuum).

So I put +'s on them. It saves me time later.

On Feb 2, 2:08 pm, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> > And I'd add use plus signs for things that are decidedly constant  
> > and not intended to be rebound, like +speed-of-light+.
>

> > Cheers,
>
> > - Chas


>
> I know such names are idiomatic in some lisps, but haven't seen them  
> very often in Clojure. Other votes yay or nay?
>

> Stu

Laurent PETIT

unread,
Feb 4, 2010, 3:10:02 AM2/4/10
to cloju...@googlegroups.com
2010/2/4 Jonathan Smith <jonathan...@gmail.com>:

> I use this convention all of the time.
>
> *var* is global-mutable
> +var+ is a global-constant
> Anything lexically bound (in a let) is 'normal'.
>
> Why do I do this?
>
> I want to differentiate between globals and lexicals.

So al your functions follow the +var+ or *var* conventions ?
I guess not.

>
> If I'm reading code (after I have long forgotten what it was the code
> was doing),
> I don't want to have to look up 'is this a variable i just bound, or
> is this a global-constant'.
>
> (A lot of the time it isn't as obvious as speed-of-light-inside-a-
> vacuum).
>
> So I put +'s on them. It saves me time later.
>
> On Feb 2, 2:08 pm, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
>> > And I'd add use plus signs for things that are decidedly constant
>> > and not intended to be rebound, like +speed-of-light+.
>>
>> > Cheers,
>>
>> > - Chas
>>
>> I know such names are idiomatic in some lisps, but haven't seen them
>> very often in Clojure. Other votes yay or nay?
>>
>> Stu
>

Chas Emerick

unread,
Feb 4, 2010, 6:34:58 AM2/4/10
to cloju...@googlegroups.com

On Feb 4, 2010, at 3:10 AM, Laurent PETIT wrote:

> 2010/2/4 Jonathan Smith <jonathan...@gmail.com>:
>> I use this convention all of the time.
>>
>> *var* is global-mutable
>> +var+ is a global-constant
>> Anything lexically bound (in a let) is 'normal'.
>>
>> Why do I do this?
>>
>> I want to differentiate between globals and lexicals.
>
> So al your functions follow the +var+ or *var* conventions ?
> I guess not.

I wouldn't use Jonathan's terminology, but:

(a) fn vars are essentially never meant to be rebound. In general,
designing an api so that a given fn is intended to be rebound is
probably a sign of things gone awry. So, no, the *var* and +var+
conventions are not germane w.r.t. fn vars.

(b) Some non-fn vars are obviously *intended* to be rebound by the
users of a namespace, whereas others simply hold what the namespace
considers to be +constants+, and rebinding such things will simply
break stuff. That's the intended distinction, and I think it's an
important one to make as it helps new users (e.g. so they don't have
to find the docstring that mentions "Don't rebind the *some-constant*
var, or you'll be sorry.") and future authors ("Vars *x* *y* and *z*
are often rebound, but *a* shouldn't ever change.").

Regardless, FWIW, I've long since backed away from promoting this for
the "official style guide" or whatever, as there's obviously a lot of
distaste for the practice.

Cheers,

- Chas

Laurent PETIT

unread,
Feb 4, 2010, 6:53:15 AM2/4/10
to cloju...@googlegroups.com
2010/2/4 Chas Emerick <ceme...@snowtide.com>:

>
> On Feb 4, 2010, at 3:10 AM, Laurent PETIT wrote:
>
>> 2010/2/4 Jonathan Smith <jonathan...@gmail.com>:
>>>
>>> I use this convention all of the time.
>>>
>>> *var* is global-mutable
>>> +var+ is a global-constant
>>> Anything lexically bound (in a let) is 'normal'.
>>>
>>> Why do I do this?
>>>
>>> I want to differentiate between globals and lexicals.
>>
>> So al your functions follow the +var+ or *var* conventions ?
>> I guess not.
>
> I wouldn't use Jonathan's terminology, but:
>
> (a) fn vars are essentially never meant to be rebound.  In general,
> designing an api so that a given fn is intended to be rebound is probably a
> sign of things gone awry.  So, no, the *var* and +var+ conventions are not
> germane w.r.t. fn vars.
>
> (b) Some non-fn vars are obviously *intended* to be rebound by the users of
> a namespace, whereas others simply hold what the namespace considers to be
> +constants+, and rebinding such things will simply break stuff.  That's the
> intended distinction, and I think it's an important one to make as it helps
> new users (e.g. so they don't have to find the docstring that mentions
> "Don't rebind the *some-constant* var, or you'll be sorry.") and future
> authors ("Vars *x* *y* and *z* are often rebound, but *a* shouldn't ever
> change.").

I have not faced the problem recently, but I guess I would do
something along those lines :

; public function, not intended to be rebound by a "client" of the
current namespace
(defn some-function [])

; private function
(defn- some-private-function [])

; public var, could be rebound by a "client" of the current namespace
(def *some-var* ... )

; private var, by definition not to be known by a "client" of the
current namespace, and thus not to be rebound by him
(def #^{:private true} *some-private-var* ...)

I also don't frequently have fns as data in the global scope, but I
guess that when I'm evolving more and more towards hof, this could
change, and then I'll also define functions that *could* be rebound by
the user, presumably seen more like functions to be passed as
arguments (function as data) than functions to be called directly by
the "client" of the namespace.
I would then follow the same convention as above, taking care of not
using defn for those functions, but rather def to promote the "this is
primarily a function-as-data" :

; public var, holding a function, could be rebound by a "client" of
the current namespace
(def *some-fn-var* (fn [] ...))

; private var, hodling a function
(def #^{:private true} *some-private-fn-var* (fn [] ...))

Following the above rules, I don't see the need to introduce the
+smth+ notation ?

>
> Regardless, FWIW, I've long since backed away from promoting this for the
> "official style guide" or whatever, as there's obviously a lot of distaste
> for the practice.
>
> Cheers,
>
> - Chas
>

Chas Emerick

unread,
Feb 4, 2010, 7:06:36 AM2/4/10
to cloju...@googlegroups.com

On Feb 4, 2010, at 6:53 AM, Laurent PETIT wrote:

> I have not faced the problem recently, but I guess I would do
> something along those lines :
>
> ; public function, not intended to be rebound by a "client" of the
> current namespace
> (defn some-function [])
>
> ; private function
> (defn- some-private-function [])
>
> ; public var, could be rebound by a "client" of the current namespace
> (def *some-var* ... )
>
> ; private var, by definition not to be known by a "client" of the
> current namespace, and thus not to be rebound by him
> (def #^{:private true} *some-private-var* ...)

Sure, marking vars that aren't part of a public API as private is
good, but that is totally orthogonal to the intention of the plus
signs, which I use to indicate rebinding intention. Some "constants"
inevitably end up needing to be public, and even those that are
private benefit from the plus signs in helping future authors know at
a glance how a var is used in the namespace.

> I also don't frequently have fns as data in the global scope, but I
> guess that when I'm evolving more and more towards hof, this could
> change, and then I'll also define functions that *could* be rebound by
> the user, presumably seen more like functions to be passed as
> arguments (function as data) than functions to be called directly by
> the "client" of the namespace.
> I would then follow the same convention as above, taking care of not
> using defn for those functions, but rather def to promote the "this is
> primarily a function-as-data" :

Yes, fns are (in my experience) almost universally created and then
passed as arguments, not bound to a var. In the one circumstance
where I did this, I believe I defined an unbound var for that purpose,
using the *earmuffs*. In any case, using ** or ++ with "normal" fn
vars seems entirely unnecessary, and I'd never suggest otherwise.

Cheers,

- Chas

Laurent PETIT

unread,
Feb 4, 2010, 8:05:29 AM2/4/10
to cloju...@googlegroups.com
2010/2/4 Chas Emerick <ceme...@snowtide.com>:

>
> On Feb 4, 2010, at 6:53 AM, Laurent PETIT wrote:
>
>> I have not faced the problem recently, but I guess I would do
>> something along those lines :
>>
>> ; public function, not intended to be rebound by a "client" of the
>> current namespace
>> (defn some-function [])
>>
>> ; private function
>> (defn- some-private-function [])
>>
>> ; public var, could be rebound by a "client" of the current namespace
>> (def *some-var* ... )
>>
>> ; private var, by definition not to be known by a "client" of the
>> current namespace, and thus not to be rebound by him
>> (def #^{:private true} *some-private-var* ...)
>
> Sure, marking vars that aren't part of a public API as private is good, but
> that is totally orthogonal to the intention of the plus signs

You're right, I don't know why I did the merge of the 2 concepts (that
was before going to lunch, maybe this explains it ? :-) ).

But then, again (and again :-), if you have only 2 "kinds" of globals,
those that are not intended to be rebound, and the others, then
certainly having 2 different ways to express them is sufficient:

*could-be-rebound*
not-intended-to-be-rebound

So I guess that by introducing +foo+, you also convey the information
that +foo+ is defined as a root var.

So a symbol can designate:

1. a global/local var
a. either intended to be rebound in dynamic scope
b. either not intended to be rebound in dynamic scope
c. can be shadowed in lexical scope
2. a formal argument of a function or macro definition
a. cannot be rebound by design, just shadowed in lexical scope
3. bound by a let
a. cannot be rebound by design, just shadowed in lexical scope

Do you feel the need to adopt a convention to distinguish symbols
representing variables in #{1. 2. 3.} ? Or just #{1. #{2. 3.}} ?
Did you never encounter the case where you use (intentionally or
rather not intentionally) the symbol of a core function as the name of
a variable in a let form ?

e.g. (let [str "foo"] ... ... ... (str "{" str <- woops :-)

> , which I use
> to indicate rebinding intention.  Some "constants" inevitably end up needing
> to be public, and even those that are private benefit from the plus signs in
> helping future authors know at a glance how a var is used in the namespace.
>
>> I also don't frequently have fns as data in the global scope, but I
>> guess that when I'm evolving more and more towards hof, this could
>> change, and then I'll also define functions that *could* be rebound by
>> the user, presumably seen more like functions to be passed as
>> arguments (function as data) than functions to be called directly by
>> the "client" of the namespace.
>> I would then follow the same convention as above, taking care of not
>> using defn for those functions, but rather def to promote the "this is
>> primarily a function-as-data" :
>
> Yes, fns are (in my experience) almost universally created and then passed
> as arguments, not bound to a var.  In the one circumstance where I did this,
> I believe I defined an unbound var for that purpose, using the *earmuffs*.
>  In any case, using ** or ++ with "normal" fn vars seems entirely
> unnecessary, and I'd never suggest otherwise.
>
> Cheers,
>
> - Chas
>

Tom Faulhaber

unread,
Feb 5, 2010, 1:21:51 AM2/5/10
to cloju...@googlegroups.com
Hmmm, the +foo+ style is used in exactly one module of contrib, repl-ln, which is not on the list of those we're considering promoting.

So if we were to adopt this standard, it would be prescriptive rather than reflecting actual practice.

Remember that this discussion concerns coding standards for clojure.lib only and should reflect only those ideas that are pretty widely used already, unless there is overwhelming agreement.

Tom

Jonathan Smith

unread,
Feb 5, 2010, 2:30:53 AM2/5/10
to Clojure Dev
No,
because I rarely rebind my functions,
where as it is fairly common to rebind global variables.

If I were to do a function that I intended to have rebound, I probably
would put earmuffs on it.

You do point out another obvious advantage,
as function vars become syntactically differentiated from variables.

I don't really think any of this is a big deal,
I just think it should be clear that there are people who do this sort
of thing and think it has advantages.

On Feb 4, 3:10 am, Laurent PETIT <laurent.pe...@gmail.com> wrote:
> 2010/2/4 Jonathan Smith <jonathansmith...@gmail.com>:

Rich Hickey

unread,
Feb 5, 2010, 7:32:59 AM2/5/10
to cloju...@googlegroups.com
On Fri, Feb 5, 2010 at 1:21 AM, Tom Faulhaber <tomfau...@gmail.com> wrote:
> Hmmm, the +foo+ style is used in exactly one module of contrib, repl-ln,
> which is not on the list of those we're considering promoting.
>
> So if we were to adopt this standard, it would be prescriptive rather than
> reflecting actual practice.
>
> Remember that this discussion concerns coding standards for clojure.lib only
> and should reflect only those ideas that are pretty widely used already,
> unless there is overwhelming agreement.
>

I'd wonder further what public constants *are* exposed by the libs.
Are there any? What are they?

Rich

Chas Emerick

unread,
Feb 5, 2010, 8:23:24 AM2/5/10
to cloju...@googlegroups.com

No, there are none. My bringing up +names-like-this+ was totally
outside the context of clojure.lib -- at some point, things veered off
into discussing conventions in general.

- Chas

Kevin Downey

unread,
Feb 11, 2010, 10:47:45 AM2/11/10
to cloju...@googlegroups.com
any library that presents an interface that implicitly passes a
parameter via dynamic binding (*db* in sql) should provide an
identical interface with the parameter passed explicitly.

> --
> You received this message because you are subscribed to the Google Groups "Clojure Dev" group.
> To post to this group, send email to cloju...@googlegroups.com.
> To unsubscribe from this group, send email to clojure-dev...@googlegroups.com.

Dimitry Gashinsky

unread,
Feb 11, 2010, 11:17:57 AM2/11/10
to cloju...@googlegroups.com

On Feb 11, 2010, at 10:47 , Kevin Downey wrote:
>>
>>> * Use good names, and don't be afraid to collide with names in other
>>> namespaces. That's what the flexible namespace support is there for.
>>
>> I agree in general, but what about clojure.core? Given the implied
>> refer-clojure in a plain (ns...), name conflicts with clojure.core are
>> a bit of a pain to handle.

I thought it is a pain, but in practice that is why refer-clojure is there and I used it couple of time for things like sftp/get which goes together with sftp/put, etc. and it makes a lot of sense too me.

>>
>>> * Be explicit and minimalist about dependencies on other
>>> packages. (Prefer the :only option to use and require).
>>
>> Again, should there be an exception for clojure.core?

I usually do not use refer-clojure unless I am overriding core symbol in my lib code. I did migrate to using :require instead of :use almost exclusively everywhere. In the project with more than one developer it helps a lot to look at the header and no exactly what is used. And more importantly be able to search for duck-stream/reader or ds/reader in the file and not just reader which could be a variable, etc.

Regards,
DiG

Stuart Halloway

unread,
Feb 12, 2010, 9:25:42 AM2/12/10
to cloju...@googlegroups.com
Nice. Added.
Reply all
Reply to author
Forward
0 new messages