(doc)strings after param in defn

442 views
Skip to first unread message

Mon Key

unread,
Dec 3, 2008, 11:35:28 PM12/3/08
to Clojure

I apologize if this has been brought up before... But, where does the
doc
string on the `my-test' defn below reside.

In case one evaluating (doc my-test returns the doc string. In case
two (doc evaluates the string as nil).

Is this value interned with the symbol and if so where and how do I
access that value.

If not, should I be able to defn with the doc string out of place
without first passing a keyword?

;;; Doc String before param
(defn my-test
"appropriately placed documentation string for my-test"
[]
(= my-test my-test))

user> (doc my-test)
-------------------------
user/my-test
([])
appropriately placed documentation string for my-test
nil

;;; Doc String after param
(defn my-test
[]
"misplaced documentation string for my-test"
(= my-test my-test))

;;;;
user> (doc my-test)
-------------------------
user/my-test
([])
nil
nil

Stephen C. Gilardi

unread,
Dec 3, 2008, 11:58:50 PM12/3/08
to clo...@googlegroups.com
On Dec 3, 2008, at 11:35 PM, Mon Key wrote:

I apologize if this has been brought up before... But, where does the doc string on the `my-test' defn below reside.

It becomes metadata for the var that your defn form defines. You can see all the metadata with (meta (var my-test)).

If not, should I be able to defn with the doc string out of place without first passing a keyword?

I don't understand the question about the keyword.

This is a valid function:

(defn hi [] "hello")

It's not a doc string out of place, it's a function that always returns the same string.

--Steve

Mon Key

unread,
Dec 4, 2008, 12:57:03 AM12/4/08
to Clojure
I'm sure I'm missing something....

Maybe I should re address the issue in a different way; outside of
`meta' what other way is there to do a *visual* check/comparison to
test if two otherwise identical and/or nearly identical symbols
contain identical slot values?

In the case where the `doc' string (disregarding whether it is
actually a doc string or not) is placed after the param how does one
catch this (mis)placement when examining the `meta' on the symbol
returns nil?

Following is the same series of evaluations at the REPL with better
annotation

;;; =======================
;;; evaluating my-test defn with doc string *after* param
;;; =======================
user> (defn my-test
[]
"misplaced documentation string for my-test"
(= my-test my-test))
#'user/my-test
;;; =======================
;;; evaluating my-test with doc string *after* param
;;; =======================
user> (my-test)
true
;;; =======================
;; examining meta of my-test defn with doc string *after* param
;;; =======================
user> (meta (var my-test))
{:ns #<Namespace user>, :file "NO_SOURCE_FILE", :name my-
test, :arglists ([]), :line 1}
;;; =======================
;;; evaluating doc of my-test defn with doc string *after* param
;;; =======================
user> (doc my-test)
-------------------------
user/my-test
([])
nil
nil
;;; =======================
;;; evaluating my-test defn with doc string *before* param
;;; =======================
user> (defn my-test
"appropriately placed documentation string for my-test"
[]
(= my-test my-test))
#'user/my-test
;;; =======================
;;; evaluating my-test with doc string *before* param
;;; =======================
user> (my-test)
true
;;; =======================
;; examining meta of my-test defn with doc string *before* param
;;; =======================
user> (meta (var my-test))
{:ns #<Namespace user>, :doc "appropriately placed documentation
string for my-test", :file "NO_SOURCE_FILE", :name my-test, :arglists
([]), :line 1}
;;; =======================
;; evaluating doc of my-test defn with doc string *before* param
;;; =======================
user> (doc my-test)
-------------------------
user/my-test
([])
appropriately placed documentation string for my-test
nil
;;; =======================

Mon Key

unread,
Dec 4, 2008, 1:08:52 AM12/4/08
to Clojure
I forgot to add the evaluations of my-test to itself

;;; =======================
;;; evaluating my-test with doc string *after* param
;;; =======================
user> my-test
#<user$my_test__2490 user$my_test__2490@58d7c2>
;;; =======================

;;; =======================
;;; evaluating my-test with doc string *before* param
;;; =======================
user> my-test
#<user$my_test__2466 user$my_test__2466@132e910>
;;; =======================

Here again the only difference is the placement of the (doc)string -
which can't be discerned visually.

Stephen C. Gilardi

unread,
Dec 4, 2008, 1:23:33 AM12/4/08
to clo...@googlegroups.com
On Dec 4, 2008, at 12:57 AM, Mon Key wrote:

I'm sure I'm missing something....

Maybe I should re address the issue in a different way; outside of
`meta' what other way is there to do a *visual* check/comparison to
test if two otherwise identical and/or nearly identical symbols
contain identical slot values?

'meta' is where the doc information is stored. Why would you rule that out?

Assume my-test appears to have a doc string. The following expression:

    (:doc (meta (var my-test)))

will return the doc string if it is correctly placed or nil if it is not.

In the case where the `doc' string (disregarding whether it is
actually a doc string or not) is placed after the param how does one
catch this (mis)placement when examining the `meta' on the symbol
returns nil?

In Clojure, symbols can name things, but do not have slots for values themselves. Vars are bound to values, including values that are functions. Reviewing the docs about this at clojure.org may help.

If I still haven't showed you how to accomplish what you're looking to accomplish, please do ask again. I'm sure as a group we can get to a useful answer.

--Steve

Mon Key

unread,
Dec 4, 2008, 1:53:20 AM12/4/08
to Clojure

So, in the case where the (doc)string is placed after the param I
should expect that REPL reads that string but doesn't necesarily
evaluate it? Where does that string go? Does it become nil? It
wasn't passed as a nil anymore than it was passed as a docstring.

If i didn't intend the (doc)string as a docstring but the reader ate
it why is it safe to assume it should become nil and vice versa?

Following defns do not evaluate as equivalent - nor are they identical
- nor do they appear to share the same identity.
I can understand cases for passing the empty string, the empty list,
etc. However, I have trouble understanding how it isn't an error/
exception to pass a non-empty string after the param list and have
that string be converted to nil.

;;;;============
(defn my-test
[]
()
(= my-test my-test))
;;;;============
(defn my-test
[]
(= my-test my-test))
;;;;============
(defn my-test
[]
"misplaced documentation string for my-test"
(= my-test my-test))
;;;;============
(defn my-test
[]
""
(= my-test my-test))
;;;;============

Meikel Brandmeyer

unread,
Dec 4, 2008, 2:22:20 AM12/4/08
to Clojure
Hi,

On 4 Dez., 07:53, Mon Key <s...@derbycityprints.com> wrote:
> So, in the case where the (doc)string is placed after the param I
> should expect that REPL reads that string but doesn't necesarily
> evaluate it?  Where does that string go? Does it become nil?  It
> wasn't passed as a nil anymore than it was passed as a docstring.

I'm not sure I understand correctly what you are asking for
but the following is my understanding what happens.

(defn foo
"docstring here"
[x y]
(+ x y))

This - as discussed before - places the string in the metadata
of the Var foo, not the function itself. Functions cannot be
associated with metadata.

(defn foo
[x y]
"some string here"
(+ x y))

This is a function which first evaluates "some string here",
which happens to evaluate to itself since it is a string. However
since the string is not the last expression of the function body
it is discarded and evaluation goes on with the next expression.

Since there is no docstring it is not assigned to the metadata
of the Var foo, which refers to the function. Hence retrieving
it will return nil.

> Following defns do not evaluate as equivalent - nor are they identical
> - nor do they appear to share the same identity.
> I can understand cases for passing the empty string, the empty list,
> etc.  However, I have trouble understanding how it isn't an error/
> exception to pass a non-empty string after the param list and have
> that string be converted to nil.

Ok. Let's try to understand what happens. Say you the second foo
function of above. Then a call (foo 1 2) is roughly equivalent to the
following:

(let [x 1
y 2]
(do
"some string here"
(+ x y)))

The part after the argument vector goes into the function body, which
is wrapped in a do. do evaluates the expressions and returns the
value of the last one. The results of evaluating the other expressions
are discarded.

So in (defn foo "string" [] ...) "string" is a docstring, while in
(defn foo [] "string" ...) "string" is part of the function body.

Hope this helps.

Sincerely
Meikel

Stuart Halloway

unread,
Dec 4, 2008, 2:55:12 AM12/4/08
to clo...@googlegroups.com
> I can understand cases for passing the empty string, the empty list,
> etc. However, I have trouble understanding how it isn't an error/
> exception to pass a non-empty string after the param list and have
> that string be converted to nil.

You are not "passing a non-empty string", you are including a String
as part of a function body. You can include any legal Clojure form in
a function body.

So for example:

(defn foo [] 1 2 3 4 5)
-> #'user/foo

(foo)
-> 5

You could ask "Where did the 1, 2, 3, and 4" go? They were evaluated,
and foo then returned the result of the final expression 5.

Many languages work this way. In Ruby:

def foo
"evaluted and lost"
"return value"
end

Cheers,
Stuart

Mon Key

unread,
Dec 4, 2008, 12:30:10 PM12/4/08
to Clojure
> The part after the argument vector goes into the function body, which
> is wrapped in a do. do evaluates the expressions and returns the
> value of the last one. The results of evaluating the other expressions
> are discarded.

Ok. That provides the clarity I was after. Thank You.

It looks like I was getting turned around by the implicit do (and by
my preconceptions coming from other Lisps where the docstring likes to
sit behind the arglist)

Maybe a common enough mistake for those making the transition...

> Many languages work this way. In Ruby:

Some don't :)

> def foo
> "evaluted and lost"
> "return value"
> end

So, it would have been safer to assume Ruby like behaviour :)

Meikel Brandmeyer

unread,
Dec 4, 2008, 5:41:26 PM12/4/08
to clo...@googlegroups.com
Hi,

Am 04.12.2008 um 18:30 schrieb Mon Key:
> It looks like I was getting turned around by the implicit do (and by
> my preconceptions coming from other Lisps where the docstring likes to
> sit behind the arglist)

This doesn't work well with Clojure, because you can have
multiple argument vectors:

(defn foo
"docstring here"
([x] (do-something-with-one-arg x))
([x y] (we-can-also-do-two x y)))

Behind which arglist should we put the docstring. ;)

>> Many languages work this way. In Ruby:
> Some don't :)

But Lisp does. (Or at least Scheme does. Can't tell for CL.)

> So, it would have been safer to assume Ruby like behaviour :)

It's never safe to assume. It's only safe to know. So
good that you ask here on the list. :)

Sincerely
Meikel


Randall R Schulz

unread,
Dec 4, 2008, 6:38:36 PM12/4/08
to clo...@googlegroups.com
On Thursday 04 December 2008 14:41, Meikel Brandmeyer wrote:
> Hi,
>
> Am 04.12.2008 um 18:30 schrieb Mon Key:
> > It looks like I was getting turned around by the implicit do (and
> > by my preconceptions coming from other Lisps where the docstring
> > likes to sit behind the arglist)
>
> This doesn't work well with Clojure, because you can have
> multiple argument vectors:
>
> (defn foo
> "docstring here"
> ([x] (do-something-with-one-arg x))
> ([x y] (we-can-also-do-two x y)))
>
> Behind which arglist should we put the docstring. ;)

Actually, I think each arity overload of a function deserves to be
independently documentable, just as each overload of a method name in a
Java class would be.

It would seem to be a syntactically upward-compatible change to allow a
doc-string before each overload's argument vector (inside the paren).

The details of what (doc ...) would present in such cases would have to
be decided and, perhaps more significantly, the way the metadata was
structured would have to be revamped, and that may entail non-
backward-compatible changes (to any code that examines the metadata on
Vars that hold functions).


And am I mistaken in my reading of the API docs for (defmulti ...) and
(defmethod ...) or is there no accommodation in either for doc-strings?
Surely that's not the case, right?


> ...
>
> Sincerely
> Meikel


Randall Schulz

Mon Key

unread,
Dec 4, 2008, 6:45:41 PM12/4/08
to Clojure
> This doesn't work well with Clojure, because you can have
> multiple argument vectors:
>
> (defn foo
> "docstring here"
> ([x] (do-something-with-one-arg x))
> ([x y] (we-can-also-do-two x y)))
>
> Behind which arglist should we put the docstring. ;)

That makes perfect sense, this is the rationale that I was missing
on...
So, is it idiomatic Clojure to wrap docstring in a #^{}?

e.g. is this considered bad form:

(defn foo
"naked docstring is ok, but rather bad form while still nice for the
relative terseness of format"
[x]
(+ x 1))

whereas this isn't:

(defn
#^{:doc "Behind which arglist should we put the docstring? Answer: A
keyword - and really one should always as a matter of habit even
though it adds a degree of syntactic eyeball mud" }
foo
([x] (do-something-with-one-arg x))
([x y] (we-can-also-do-two x y)))


> smime.p7s
> 5KViewDownload

J. McConnell

unread,
Dec 4, 2008, 7:16:03 PM12/4/08
to clo...@googlegroups.com
On Thu, Dec 4, 2008 at 6:45 PM, Mon Key <st...@derbycityprints.com> wrote:
>
> So, is it idiomatic Clojure to wrap docstring in a #^{}?
>
> e.g. is this considered bad form:
>
> (defn foo
> "naked docstring is ok, but rather bad form while still nice for the
> relative terseness of format"
> [x]
> (+ x 1))

Nope, that's the norm :)

- J.

Meikel Brandmeyer

unread,
Dec 5, 2008, 2:23:33 AM12/5/08
to Clojure
Hi,

On 5 Dez., 00:38, Randall R Schulz <rsch...@sonic.net> wrote:
> Actually, I think each arity overload of a function deserves to be
> independently documentable, just as each overload of a method name in a
> Java class would be.

I disagree. If the function of the function changes that much, that
you need a different docstring just because you pass in a different
number of arguments then there is something terribly smelly.

What are the major use cases of variable arity?

For me this is default values:

(get a-map a-thing the-default) vs. (get a-map a-thing)
(sort comparator a-collection) vs. (sort a-collection)

This does not deserve a different docstring. This can be well
handled in one.

> The details of what (doc ...) would present in such cases would have to
> be decided and, perhaps more significantly, the way the metadata was
> structured would have to be revamped, and that may entail non-
> backward-compatible changes (to any code that examines the metadata on
> Vars that hold functions).

I don't think, that this change is worth the trouble.

> And am I mistaken in my reading of the API docs for (defmulti ...) and
> (defmethod ...) or is there no accommodation in either for doc-strings?
> Surely that's not the case, right?

You can always use:

(defmulti #^{:arglists '([a b] [a b c]) :doc "bla"} foo identity)

Docstrings for individual defmethods are not possible. While
I also wanted to use it before. Rich convinced me, that it is
a smell when I have to.

Sincerely
Meikel

Randall R Schulz

unread,
Dec 5, 2008, 9:22:27 AM12/5/08
to clo...@googlegroups.com
On Thursday 04 December 2008 23:23, Meikel Brandmeyer wrote:
> Hi,
>
> On 5 Dez., 00:38, Randall R Schulz <rsch...@sonic.net> wrote:
> > ...
> ...

>
> > And am I mistaken in my reading of the API docs for (defmulti ...)
> > and (defmethod ...) or is there no accommodation in either for
> > doc-strings? Surely that's not the case, right?
>
> You can always use:
>
> (defmulti #^{:arglists '([a b] [a b c]) :doc "bla"} foo identity)

Why all the circumlocutions to bring a multimethod up to the level of
documentation support of a plain function?

Reply all
Reply to author
Forward
0 new messages