Namespaces, use, and refer

5 views
Skip to first unread message

Konrad Hinsen

unread,
Mar 2, 2009, 3:53:59 AM3/2/09
to Clojure
Over the last weeks, two additions to clojure.core broke several of
my library modules by introducing names into the clojure.core
namespace that I was using in my libraries as well. While this kind
of problem is acceptable in a pre-release development period, I don't
expect it to go away with release 1.0, so I believe we need to do
something about it.

Basically, the problem concerns access to other namespaces via :use
or :refer, though in practice it is most important for clojure.core
that is referred to by default in any namespace. A symbol that refers
to a var from another namespace cannot be redefined. If I introduce a
symbol in my namespace and in a later release the same symbol is
defined in a namespace that mine refers to, I can no longer compiler
my namespace.

For namespaces other than clojure.core, an acceptable solution is to
use the :only keyword in the :use clause of the ns macro. This just
requires a bit more work in typing, but I don't see any other
potential difficulty. I am currently converting all my code to
use :only, and I haven't had any bad surprises until now. For
clojure.core, listing all imported symbols explicitly would be a real
pain, but I don't see any other simple solution. I just hope someone
else does :-)

Konrad.

srolls

unread,
Mar 2, 2009, 12:35:31 PM3/2/09
to clo...@googlegroups.com
I think :exclude is what you want

(ns my-ns
  (:refer-clojure :exclude [get replace]))

Konrad Hinsen

unread,
Mar 2, 2009, 12:49:13 PM3/2/09
to clo...@googlegroups.com
On Mar 2, 2009, at 18:35, srolls wrote:

> I think :exclude is what you want
>
> (ns my-ns
> (:refer-clojure :exclude [get replace]))

Not quite, as exclude requires me to know what I want exclude.

What I want is "exclude everything that wasn't there in version X.Y".

Konrad.

Antony Blakey

unread,
Mar 2, 2009, 5:30:57 PM3/2/09
to clo...@googlegroups.com

On 02/03/2009, at 7:23 PM, Konrad Hinsen wrote:

> For namespaces other than clojure.core, an acceptable solution is to
> use the :only keyword in the :use clause of the ns macro. This just
> requires a bit more work in typing, but I don't see any other
> potential difficulty. I am currently converting all my code to
> use :only, and I haven't had any bad surprises until now. For
> clojure.core, listing all imported symbols explicitly would be a real
> pain, but I don't see any other simple solution. I just hope someone
> else does :-)

I'm a clojure newb, but couldn't you reflect on a given version to
generate an import file that used :only to import every name visible
in that version? Then you could import that file, which would be a
version constant (although I'm not clear yet if clojure allows
transitive imports). It should be easy to generate such a file
privately for any given snapshot (although I imagine it would be best
as an official version artifact).

Alternatively of course every name could be tagged with version
metadata and import enhanced to take a version spec, but that seems
far more intrusive (and in any case precisely equivalent to my first
suggestion).

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

There are two ways of constructing a software design: One way is to
make it so simple that there are obviously no deficiencies, and the
other way is to make it so complicated that there are no obvious
deficiencies.
-- C. A. R. Hoare


Laurent PETIT

unread,
Mar 2, 2009, 6:53:35 PM3/2/09
to clo...@googlegroups.com
Konrad,

I'm able to do that from the REPL when done one by one :
(clojure.core/ns-unmap *ns* (quote filter))
(clojure.core/defn filter [] "oh my!")

thus correctly redefining the binding of filter for the rest of use by the ns

But I can't manage to get it work from a macro (indeed not even when directly called inside a do) :

(do (clojure.core/ns-unmap *ns* (quote filter)) (clojure.core/defn filter [] "my map!"))

What is wrong with me ? (Something with def I still haven't understood, I think)

Thanks in advance,

--
laurent

2009/3/2 Konrad Hinsen <konrad...@laposte.net>

Konrad Hinsen

unread,
Mar 3, 2009, 2:35:00 AM3/3/09
to clo...@googlegroups.com
On 03.03.2009, at 00:53, Laurent PETIT wrote:

> I'm able to do that from the REPL when done one by one :
> (clojure.core/ns-unmap *ns* (quote filter))
> (clojure.core/defn filter [] "oh my!")
>
> thus correctly redefining the binding of filter for the rest of use
> by the ns
>
> But I can't manage to get it work from a macro (indeed not even
> when directly called inside a do) :
>
> (do (clojure.core/ns-unmap *ns* (quote filter)) (clojure.core/defn
> filter [] "my map!"))
>
> What is wrong with me ? (Something with def I still haven't
> understood, I think)

I can only confirm your observation, and say that I don't understand
it either!

Konrad.

Christophe Grand

unread,
Mar 3, 2009, 3:04:33 AM3/3/09
to clo...@googlegroups.com
Konrad Hinsen a écrit :
In the first case, when you enter the second statement at the repl,
filter is unmapped already so the compiler understands that it must
create a var and intern it as my-ns/filter.
In the second case, both statements are bundled in one expression: when
the expression is compiled filter is still mapped in the current ns and
the compiler refuses to compile the def form.

Adding an eval can make that works:

(do
(clojure.core/ns-unmap *ns* (quote filter))

(eval '(clojure.core/defn filter [] "my map!")))


but it may be simpler to explore doing something like this:

(do
(clojure.core/ns-unmap *ns* (quote filter))

(clojure.lang.Var/intern *ns* 'filter (fn[] "my map!")))


Christophe

--
Professional: http://cgrand.net/ (fr)
On Clojure: http://clj-me.blogspot.com/ (en)


Laurent PETIT

unread,
Mar 3, 2009, 4:20:05 AM3/3/09
to clo...@googlegroups.com
So there we are with a version of defn, which I called defn! because it is even more agressive than defn in its side effects, that could solve your problem :

(defmacro defn!
  "Like defn, but first ensures that if name is bound to something (e.g. the name of a function
   in a 'used' or 'required' namespace, it is first unbound)."
  [name & body]
  `(do
     (clojure.core/ns-unmap *ns* (quote ~name))
     (eval (quote (clojure.core/defn ~name ~@body)))))

I chose to use eval, even if it's not the usual recommended way, because I really wanted to not duplicate the logic in defn regarding definition of multiple arity functions, meta data, ...

But I'm not sure it is correct to have twice ~name in the macro expansion. I thought that as name is expected to be the name for a symbol without evaluation (as is required for the name in defn), I could do this ?

If you find this interesting, please feel free to add it to clojure-contrib.

I think the same thing could be done for defmacro (defmacro!), ... and other defXYZ.. functions/macros as well .. ?

HTH,

--
Laurent


2009/3/3 Christophe Grand <chris...@cgrand.net>

Laurent PETIT

unread,
Mar 3, 2009, 4:37:34 AM3/3/09
to clo...@googlegroups.com
Now that I rethink about it, wouldn't this version using eval be less than ideal as far as AOT compilation is concerned ?

2009/3/3 Laurent PETIT <lauren...@gmail.com>

Laurent PETIT

unread,
Mar 3, 2009, 4:49:10 AM3/3/09
to clo...@googlegroups.com
Please forgive about this defn! macro, it does not seem to play well in practice.

I now share Konrad's thoughts : I don't know if what he want is feasible without changes in clojure, or use of clojure non-public APIs.

2009/3/3 Laurent PETIT <lauren...@gmail.com>
Reply all
Reply to author
Forward
0 new messages