1

According to spec, def should intern the var in the current ns (i.e. *ns*). However, the following code does not look anything like it:

(ns namespace-b)

(defn def_something []
  (ns namespace-a)
  (println *ns*) ;prints namespace-a as it should
  (def something 1)
) 

(def_something)

(println namespace-b/something) ; prints 1 
(println namespace-a/something) ; throws

What am I missing?

Notes:

  • defn is used just for clarity. Defining and running anonymous function works just as well.
  • I know that using def inside function is probably not very idiomatic. However, this is just extracted essence of a bigger problem I ran into.
Tomas Kulich
  • 14,388
  • 4
  • 30
  • 35
  • Not only is `def` inside a function not idiomatic, it doesn't do what you would expect it to (as you are learning). Better to use `intern` directly, or at least use a macro so that the def does its thing in the proper namespace. – noisesmith Oct 27 '14 at 16:43

2 Answers2

3

The parser already interns the var to the current namespace at compile time, although it won't be bound immediately:

(defn dd [] (def x 0))
x ;; => #<Unbound Unbound: #'user/x>

The relevant piece of code can be found here, with the second parameter to lookupVar triggering the aforementioned interning for non-existing vars here.

The parses then generates an expression that references the previously created var, so the expression logic never leaves the current namespace.

TL;DR: def is something that the compiler handles in a special kind of way.

xsc
  • 5,983
  • 23
  • 30
  • I understand that, but does that mean the spec should be corrected? I don't see a correct description of 'def' anywhere. – Tomas Kulich Oct 27 '14 at 17:01
  • 1
    Another related problem: You start Leinigen project from scratch. Define function 'myfunc' and call it from the '-main'. This works although IMO it shouldn't - note that Leiningen runs the -main in the newly created 'user' namespace which does not contain 'myfunc' neither as an alias, nor as a refer. It's just the consequence of a strange 'def' behavior, that such code is working. Moreover, if you run (eval '(myfunc)) in the -main, it crashes (as IMO it should). Now if you run the code directly (without Leiningen) everything works fine. I understand what's going on here, but man, it is ugly. – Tomas Kulich Oct 27 '14 at 17:13
  • in what namespace is `myfunc` defined? why shouldn't it be visible from `-main`? I don't get it. – noisesmith Oct 27 '14 at 19:53
  • If `myfunc` is defined in the same namespace as `-main` this is normal, and expected behavior by the way. Names are resolved based on the namespace in which the code is compiled. – noisesmith Oct 27 '14 at 19:54
  • if you examine the code: https://gist.github.com/tomaskulich/57fba595484e5e8e1a82 you might see what i'm talking about. The funny thing here is, that if you run the -main function with clojure interpreter (i.e. you change the code such as https://gist.github.com/tomaskulich/5df430449e9b027fe893), everything works fine (because the interpreter does not create its own namespace for running the code). – Tomas Kulich Oct 30 '14 at 21:12
1

The key thing to understand about def is that it is a macro. This means that it does not resolve the namespace or create the binding at runtime, but beforehand, while the code is being compiled.

If you call a function that calls def, that call to def was already resolved to use the namespace in which the function was defined. Similarly, if you call functions inside a function body, the functions to call are resolved at compile time within the namespace where that function was defined.

If you want to generally bind values to namespaces at runtime, you should use the function intern, which lets you explicitly set the namespace to mutate.

All this said, namespace mutation is just that, it's procedural and is not thread safe and does not have nice declarative semantics like other options Clojure makes available. I would strongly suggest finding a way to express your solution that does not involve unsafe runtime mutation.

noisesmith
  • 20,076
  • 2
  • 41
  • 49