Why no def- ?

205 views
Skip to first unread message

Alex Baranosky

unread,
Jan 21, 2011, 12:40:04 AM1/21/11
to clo...@googlegroups.com
I've wanted to have private defs.  For defn, I just us defn-.  But there is no def-

So I just use:

(defmacro def- [name & decls]
    (list* `def (with-meta name (assoc (meta name) :private true)) decls))

Ken Wesson

unread,
Jan 21, 2011, 12:51:58 AM1/21/11
to clo...@googlegroups.com

There's a (defvar- ...) in clojure.contrib. Why there's nothing like
this in core remains a mystery to me. :)

Aaron Bedra

unread,
Jan 21, 2011, 8:21:22 AM1/21/11
to clo...@googlegroups.com
On 01/21/2011 12:51 AM, Ken Wesson wrote:
> On Fri, Jan 21, 2011 at 12:40 AM, Alex Baranosky
> <alexander...@gmail.com> wrote:
>> I've wanted to have private defs. For defn, I just us defn-. But there is
>> no def-
>>
>> So I just use:
>>
>> (defmacro def- [name& decls]

>> (list* `def (with-meta name (assoc (meta name) :private true)) decls))
> There's a (defvar- ...) in clojure.contrib. Why there's nothing like
> this in core remains a mystery to me. :)
>
You can also do

(def foo {:private true} (...))

which is just the basic functionality in core.

Cheers,

Aaron Bedra
--
Clojure/core
http://clojure.com

Stuart Sierra

unread,
Jan 21, 2011, 9:19:09 AM1/21/11
to clo...@googlegroups.com
And in Clojure 1.3:   (def ^:private foo ...)

-Stuart Sierra
Clojure/core

Laurent PETIT

unread,
Jan 21, 2011, 9:22:06 AM1/21/11
to clo...@googlegroups.com
2011/1/21 Aaron Bedra <aaron...@gmail.com>

On 01/21/2011 12:51 AM, Ken Wesson wrote:
On Fri, Jan 21, 2011 at 12:40 AM, Alex Baranosky
<alexander...@gmail.com>  wrote:
I've wanted to have private defs.  For defn, I just us defn-.  But there is
no def-

So I just use:

(defmacro def- [name&  decls]
    (list* `def (with-meta name (assoc (meta name) :private true)) decls))
There's a (defvar- ...) in clojure.contrib. Why there's nothing like
this in core remains a mystery to me. :)

You can also do

(def foo {:private true} (...))

With def, it will be :
user=> (def ^{:private true} foo "ba")
#'user/foo
user=> (meta (var foo))
{:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 4, :private true}
user=>

It's with defn that you can use a map at a certain position:
user=> (defn foo {:private true} [] "bar")
#'user/foo
user=> (meta (var foo))
{:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 7, :arglists ([]), :private true}
user=>


Cheers,

--
Laurent

Aaron Bedra

unread,
Jan 21, 2011, 9:49:52 AM1/21/11
to clo...@googlegroups.com
Doh!  I'm full of typos this week.  Do a combination of what I meant and what Laurent said and you'll be in a good place.

Ken Wesson

unread,
Jan 21, 2011, 3:38:22 PM1/21/11
to clo...@googlegroups.com

It's still odd that defvar- isn't in core. Explicit metadata is clunky
compared to defn-.

Another thing -- defn docstrings. It would be nice if:

1. You could optionally put a docstring after the value of a normal
def -- (def foo 17 "seventeen").

2. A function body that starts with a string and isn't only the
string is treated as if the string were a docstring, so

(defn foo
"Docstring -- works currently"
([x y]
(+ (* x x) y)))

and the imo tidier with only one arity

(defn foo [x y]
"Docstring -- works currently"
(+ (* x x) y))

would be equivalent.

(defn foo
"Docstring -- works currently"
[x y]
(+ (* x x) y))

should probably also work (it currently doesn't -- the function
works but the docstring disappears). Obviously

(defn foo []
"Hello, World")

would still have to return "Hello, World", hence the requirement
that the defn body discards the string rather than returns it.

3. Multiple string literals in a row could be used.

(defn foo
"Docstring line 1
Docstring line 2
Lines 3 and on ..."
([x y]
(+ (* x x) y)))

has lines 2 and up begin with a lot of spaces. If these are
kept, it will print as

Docstring line 1
Docstring line 2
Lines 3 and on ...

If they are not, then a docstring containing


...
Example usage:

(mymacro foo [a 17 b 32]
(dosync ...
(blah blah ...)))

is going to lose the indents in the example lines. And of course

(defn foo
"Docstring line 1
Docstring line 2
Lines 3 and on ..."
[x y]
(+ (* x x) y))

is butt-ugly.

(defn foo
"Docstring line 1"
"Docstring line 2"
"Lines 3 and on ..."
[x y]
(+ (* x x) y))

if it worked would avoid that trilemma; docstring lines would
start with only the leading spaces actually intended to be
included in the text, so the entire tool chain could preserve
them and get the desired results.

If combined with 2 above, this would mean that any function whose
s-expression was (defn symbol vector string-literal string-literal
... string-literal at-least-one-more-thing) would have the chain
of string literals treated as docstring lines, with the
at-least-one-more-thing as the body. Anything from the first
non-string-literal on would be the body; if there was nothing in
there but string literals after the argvec the final string
literal would be taken as the return value rather than a doc line.

Note: the docstring literals under this proposal will tend to not
contain newlines. (interpose \newline string-literal-seq) should
therefore be used to combine the literals into the docstring.

3 can be applied to the hypothetical def docstrings as well:

(def name val line1 line2 ... linen)

would be equivalent to

(def ^{:doc (interpose \newline [line1 line2 ... linen]) name val)

Another thing that could be useful: if the entire s-expression (def
...) or (defn ...) has metadata, merge it in, and if there's more than
one
meta, merge rather than replace. This would allow a style that didn't
cause longer documentation strings to separate the function name from
the body, and where indent is less of an issue:

^{:doc "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum."}

^{:private true :tag String}

(defn foo ...)

It'd also be less awkward when setting flags and hinting return type.

Sean Corfield

unread,
Jan 21, 2011, 6:15:10 PM1/21/11
to clo...@googlegroups.com
On Fri, Jan 21, 2011 at 12:38 PM, Ken Wesson <kwes...@gmail.com> wrote:
> Another thing that could be useful: if the entire s-expression (def
> ...) or (defn ...) has metadata, merge it in, and if there's more than
> one
> meta, merge rather than replace.

That's how Clojure 1.3 already works...

user=> (defn ^:private ^:stuff ^{:doc "Docs"} ^{:more "info"} foo [] "")
#'user/foo
user=> (meta #'user/foo)
{:arglists ([]), :ns #<Namespace user>, :name foo, :private true,
:more "info", :doc "Docs", :stuff true, :line 7, :file
"NO_SOURCE_PATH"}
--
Sean A Corfield -- (904) 302-SEAN
Railo Technologies, Inc. -- http://getrailo.com/
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

Benjamin Teuber

unread,
Jan 22, 2011, 10:24:05 AM1/22/11
to Clojure
I think a def- definitely belongs in core for consistency reasons.
So I'm writing a ticket and patch now.

Cheers, Benjamin

Stuart Halloway

unread,
Jan 22, 2011, 10:27:44 AM1/22/11
to clo...@googlegroups.com
Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..

Stu

Stuart Halloway
Clojure/core
http://clojure.com

> I think a def- definitely belongs in core for consistency reasons.
> So I'm writing a ticket and patch now.
>
> Cheers, Benjamin
>

> --
> 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


Ken Wesson

unread,
Jan 22, 2011, 10:30:28 AM1/22/11
to clo...@googlegroups.com
On Sat, Jan 22, 2011 at 10:27 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..

"We" do? Who is "we" and why does this "we" want doing this to be slightly ugly?

Stuart Halloway

unread,
Jan 22, 2011, 10:39:16 AM1/22/11
to clo...@googlegroups.com
> 1. You could optionally put a docstring after the value of a normal
> def -- (def foo 17 "seventeen").
>

def has supported an optional doc string since 1.2. I have just updated the wiki and docstring to reflect this.

> (defn foo
> "Docstring -- works currently"
> [x y]
> (+ (* x x) y))

AFAIK this has always worked. If you see this not working, please post details to reproduce.

Cheers,

Stuart Halloway

unread,
Jan 22, 2011, 10:48:27 AM1/22/11
to clo...@googlegroups.com
>> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..
>
> "We" do? Who is "we" and why does this "we" want doing this to be slightly ugly?

The Clojure/core team is led by its technical advisors, Rich Hickey and myself. In this particular case, I was on the fence and Rich called it.


Ken Wesson

unread,
Jan 22, 2011, 10:52:03 AM1/22/11
to clo...@googlegroups.com
On Sat, Jan 22, 2011 at 10:39 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
>> 1. You could optionally put a docstring after the value of a normal
>>   def -- (def foo 17 "seventeen").
>
> def has supported an optional doc string since 1.2. I have just updated the wiki and docstring to reflect this.

My Clojure 1.2 REPL says otherwise:
user=> (def x 32 "foo")
#<CompilerException java.lang.Exception: Too many arguments to def
(NO_SOURCE_FILE:73)>

>> (defn foo
>>     "Docstring -- works currently"
>>     [x y]
>>     (+ (* x x) y))
>
> AFAIK this has always worked. If you see this not working, please post details to reproduce.

Actually, it quasi-works. In both cases the var gets :doc "string"
metadata. Only if the arity implementation is wrapped in parentheses
does the function object itself also get the :doc "string" metadata.
(And the arities metadata, and a lot of other metadata.)

user=> (defn bar "foo" [x] (* x x))
#'user/bar
user=> (meta bar)


{:ns
#<Namespace user>,

:name bar}
user=> (meta #'bar)


{:ns
#<Namespace user>,

:name bar,
:file
"NO_SOURCE_PATH",
:line 74,
:arglists ([x]),
:doc "foo"}
user=> (defn bar "foo" ([x] (* x x)))
#'user/bar
user=> (meta bar)


{:ns
#<Namespace user>,

:name bar,
:file
"NO_SOURCE_PATH",
:line 74,
:arglists ([x]),
:doc "foo"}
user=> (meta #'bar)


{:ns
#<Namespace user>,

:name bar,
:file
"NO_SOURCE_PATH",
:line 77,
:arglists ([x]),
:doc "foo"}
user=>

Ken Wesson

unread,
Jan 22, 2011, 10:52:33 AM1/22/11
to clo...@googlegroups.com

OK, that answers the first question, but not the second. What was
Rich's rationale?

Stuart Halloway

unread,
Jan 22, 2011, 11:13:56 AM1/22/11
to clo...@googlegroups.com
>>>> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..
>>>
>>> "We" do? Who is "we" and why does this "we" want doing this to be slightly ugly?
>>
>> The Clojure/core team is led by its technical advisors, Rich Hickey and myself. In this particular case, I was on the fence and Rich called it.
>
> OK, that answers the first question, but not the second. What was
> Rich's rationale?

I have started a wiki page "Why Feature X Was Declined" [1]. The def- variants are right where they should be: in a contrib library for people that need them.

Stuart Halloway
Clojure/core
http://clojure.com

[1] http://dev.clojure.org/display/design/Why+Feature+X+Was+Declined

Ken Wesson

unread,
Jan 22, 2011, 12:29:08 PM1/22/11
to clo...@googlegroups.com
On Sat, Jan 22, 2011 at 11:13 AM, Stuart Halloway
<stuart....@gmail.com> wrote:
>>>>> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..
>>>>
>>>> "We" do? Who is "we" and why does this "we" want doing this to be slightly ugly?
>>>
>>> The Clojure/core team is led by its technical advisors, Rich Hickey and myself.  In this particular case, I was on the fence and Rich called it.
>>
>> OK, that answers the first question, but not the second. What was
>> Rich's rationale?
>
> I have started a wiki page "Why Feature X Was Declined" [1]. The def- variants are right where they should be: in a contrib library for people that need them.

I was expecting a list of specific features and the rationales for
declining them, including def-, but there's nothing there but generic
reasons why some features may have been rejected.

In particular, there's no rationale apparent for including defn- in
core but not including def- in core; the implication of what text IS
at the web page you linked is that they should probably either both be
in core or both be in contrib.

Benjamin Teuber

unread,
Jan 23, 2011, 4:28:42 AM1/23/11
to Clojure
<stuart.hallo...@gmail.com> wrote:>> Please don't. It has already been
discussed and declined. The metadata is uglier because we want doing
this to be slightly ugly..

Sorry, didn't get your response in time..
Anyways, I agree with Ken it seems weird to have defn- in core and not
def- - or is defn- sort of deprecated in favour of ^:private ?

OGINO Masanori

unread,
Jan 24, 2011, 12:41:24 AM1/24/11
to clo...@googlegroups.com
Hello.

Sorry to cut in, but I agree with Ken, too.
If defn- should be in core and def- shouldn't, it seems asymmetric.
Showing why there is asymmetric design may leads to positive
discussion, I think.

Thank you.

--
Name: OGINO Masanori (荻野 雅紀)
E-mail: masanor...@gmail.com

Jeff Rose

unread,
Jan 24, 2011, 7:25:24 PM1/24/11
to Clojure
On Jan 22, 5:13 pm, Stuart Halloway <stuart.hallo...@gmail.com> wrote:
> >>>> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..

> >> The Clojure/core team is led by its technical advisors, Rich Hickey and myself.  In this particular case, I was on the fence and Rich called it.
>
> > OK, that answers the first question, but not the second. What was
> > Rich's rationale?
>
> I have started a wiki page "Why Feature X Was Declined" [1]. The def- variants are right where they should be: in a contrib library for people that need them.

This is something I run into all the time, and I end up just sort of
shrugging and thinking, "ahhh screw it, let these constants pollute
the namespace and I'll deal with it later if it causes problems." For
the same reasons that someone wouldn't want to export function names,
why would anything be different for other vars? For now I'm happy to
use contrib, but it seemed a reasonable question to me.

Thanks,
Jeff

Nick Brown

unread,
Jan 24, 2011, 8:42:31 PM1/24/11
to Clojure
Ugly? Aww, I thought the ^ metadata looked kinda cute...

It is a bit awkward that defn- exists and not def-, but it seems defs
are not going to be as common as defns (though I'll admit I haven't
written or read enough complex idiomatic Clojure code to know for
sure). And if you really want to be consistent you would probably
also want defmulti-, defmacro-, defstruct-, defprotocol-, etc. And
I'll have to stop using tiny fonts to read Clojure code so I can tell
if something is private or not.

If we really wanted to make it easy to write private functions,
variables, etc, I would personally prefer a macro like (private) for
which all forms inside would be made private. Like
(private
(def my-private-foo (...))
(defn my-private-bar [] (...)))

Not only does that seem more clear, it would encourage the private
stuff to be separate from public stuff.

On Jan 22, 10:27 am, Stuart Halloway <stuart.hallo...@gmail.com>
wrote:
> Please don't. It has already been discussed and declined. The metadata is uglier because we want doing this to be slightly ugly..
>
> Stu
>
> Stuart Halloway
> Clojure/corehttp://clojure.com

Ken Wesson

unread,
Jan 24, 2011, 9:22:12 PM1/24/11
to clo...@googlegroups.com
On Mon, Jan 24, 2011 at 8:42 PM, Nick Brown <nwb...@gmail.com> wrote:
> Ugly?  Aww, I thought the ^ metadata looked kinda cute...
>
> It is a bit awkward that defn- exists and not def-, but it seems defs
> are not going to be as common as defns (though I'll admit I haven't
> written or read enough complex idiomatic Clojure code to know for
> sure).  And if you really want to be consistent you would probably
> also want defmulti-, defmacro-, defstruct-, defprotocol-, etc.  And
> I'll have to stop using tiny fonts to read Clojure code so I can tell
> if something is private or not.
>
> If we really wanted to make it easy to write private functions,
> variables, etc, I would personally prefer a macro like (private) for
> which all forms inside would be made private.  Like
> (private
>  (def my-private-foo (...))
>  (defn my-private-bar [] (...)))
>
> Not only does that seem more clear, it would encourage the private
> stuff to be separate from public stuff.

First stab at it:

(defmacro private [& forms]
(apply list 'do
(map
(fn [form]
(cond
(not (coll? form)) form
(or (vector? form) (map? form) (set? form)) form
(< (count form) 2) form
:else
(let [[d n & r] form]
(cond
(not (symbol? d)) form
(not (symbol? n)) form
(not (.startsWith (str d) "def")) form
:else (apply list d (vary-meta n assoc :private true) r)))))
forms)))

It seems to work. It just outputs all the enclosed forms in a "do",
except for those that start (defsomething somesymbol ...), where it
vary-metas a :private true onto somesymbol. So, the form must start
with two symbols and the first symbol must start with "def".

OGINO Masanori

unread,
Jan 24, 2011, 9:44:03 PM1/24/11
to clo...@googlegroups.com
Hello.

> And if you really want to be consistent you would probably
> also want defmulti-, defmacro-, defstruct-, defprotocol-, etc.

In my opinion, if defn- is not in core but in contrib, I feel "be consistent".
By the way, defstruct- and defmacro- is in contrib consistently :-)

> If we really wanted to make it easy to write private functions,
> variables, etc, I would personally prefer a macro like (private) for
> which all forms inside would be made private. Like
> (private
> (def my-private-foo (...))
> (defn my-private-bar [] (...)))

I like this macro and I'm ashamed that I've never hit on such idea!

Benjamin Teuber

unread,
Jan 25, 2011, 11:31:21 AM1/25/11
to Clojure
Ok, I think I've got it - so basically all private variants should go
in contrib now and moving defn- now would break a lot of people's code
"just" for a little more coherency.

But in this case, I'd like def- to be included in clojure.contrib.def.
I dislike defvar as it's just name and docstring positions are non-
clojuresque (no surprise with a Common Lisp macro).

I like the private macro btw. - maybe also put this in contrib.def?

OGINO Masanori

unread,
Jan 25, 2011, 10:25:57 PM1/25/11
to clo...@googlegroups.com
Hello.

If def- remains for historical reason, def- may be marked as
duplicated and will be moved, for example, in 1.4, 2.0 or so?

Reply all
Reply to author
Forward
0 new messages