1

My background includes 10 years of common lisp so now I am learning Clojure by writing a symbolic math package with vector (i.e. a, b, c) and Nvector bindings (ab, ac, bc, etc) in namespaces, with the print method defined for these objects.

So when I wrote my deftests in the bottom of the same file as where the binding functions, I had to write (declare a b ab) to avert compiler warnings (which makes perfect sense).

    (def G3 (doall (ga-bindall "a b c")))
    galg.core=> G3
    (+a +b +c +a*b +a*c +b*c +a*b*c +a*b +a*c +b*c +a*b*c)
    galg.core=> [a +a -a ab +ab -ab a*b +a*b -a*b abc]
    [+a +a -a +a*b +a*b -a*b +a*b +a*b -a*b a*b*c]

    (deftest galg-vectors
      (declare a b ab)   ;<=== required when in same file as definitions
      (testing "GALG Vector, Nvector and Sum tests."
        (is (= (Vector 'a) a))
        (is (= (Vector 'a -1) -a))
        (is (= ab (Nvector 'a 'b)))
        (is (= (+ 1 a ab) (Sum 1 a ab)))
        ))

Then when I cleaned up my code by moving the tests to, galg.core-test file as here:

    (ns galg.core-test (:use clojure.test galg.core))  ;;<== imports a, b, ab, etc
    (deftest galg-vectors
      ;(declare a b ab)   ;<=== must be removed when in separate file 
      (testing "GALG Vector, Nvector and Sum tests."
        (is (= (Vector 'a) a))
        (is (= (Vector 'a -1) -a))
        (is (= ab (Nvector 'a 'b)))
        (is (= (+ 1 a ab) (Sum 1 a ab)))
        ))

... then, the "already refers to:" compiler error occurs when the (declare a b ab) is present:

CompilerException java.lang.IllegalStateException: a already refers to: #'galg.core/a in namespace: galg.core-test, compiling:(NO_SOURCE_PATH:2:3)

This error seems a bit excessive, since from my thinking, "declare" is really the "promise of a binding" for the compiler, without really defining one.

Any thoughts?

2 Answers 2

1

declare is not quite that smart, it doesn't really create the promise that something will be created later, rather it creates it now, and it always creates it in the local namespace, it then leaves it up to you to make sure that it gets a value before it is used, otherwise an exception will be thrown when you try to use the unbound value for something requiring a bound value. def is smart enough to not overwrite a bound value with an unbound one in the case where it was previously defined.

user> (macroexpand-1 '(declare a))
(do (def a)) 

As you can see, declare declare creates local vars with unbound values it is this local var creation that is triggering the error you see. Because the namespace (`ns) expression already added an entry with that name to your namespace, when your expression:

 (declare a b ab) 

runs it will expand to:

 (do (def a) (def b) (def ab))

which will attempt to create a var in the local namespace named a which triggers the error because that name already refers to another namespace.

Sign up to request clarification or add additional context in comments.

3 Comments

It is too late for me to remove my upvote, but it turns out this is wrong. You can declare and def in any order within a namespace, the error is caused by use semantics between namespaces.
perhaps wrong is putting it too strongly - but incomplete, and not quite hitting the source of the problem
I will edit to make it more complete, If you still feel it's wrong this will give you a chance to remove your vote, Though I would rather improve the answer until it meats muster ;)
0

If it is done within the same namespace, you can def and declare in any order without error.

user> (def a 0)
#'user/a
user> (declare a)
#'user/a

The problem is that all clojure variables are namespaced. A declare creates the variable in the namespace where it is invoked. Because you have invoked use to refer to the symbols from another namespace, declaring them creates new variables galg.core-test/a, etc., which shadow the ones you were using, galg.core/a etc. The error message is telling you that an unrelated var is shadowing the one previously in scope because of use.

2 Comments

And, editorially, things like this are why I avoid use or even refer. Things stay much clearer when you have an explicit namespace on each symbol that is not from your current namespace or clojure.core.
Thanks for all the comments and discussion, since slightly different than common lisp. The purpose for "use", is because I'm using the repl to access the short names of vector bindings (def a (Vector 'a)) and (def ab (Nvector 'a 'b)) etc, which can be used such as (+ a ab). So don't want to use fully qualified namespace names galg.core/a or even using :as alias of g/a.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.