On Oct 2, 2009, at 10:29 AM, Mark wrote:
Is there a way to make a declaration in Clojure that cannot be rebound later? Ideally, I'd like something that fails if I try to do this:(def myname "mark") ; ...more code, elided... (def myname "Mark")
Along these lines, I was thinking of adding defconst to clojure.contrib.def. It's like Common Lisp's defconst, but the fact that its value isn't allowed to change is enforced:
(defmacro defconst"Defines a var with a constant value and optional doc string. Any attempt to redefine, bind, or set! the const to a different value will throw an
exception." ([name init] `(do (set-validator! (defvar ~name ~init) #{~init}) (var ~name))) ([name init doc] `(defconst ~(with-meta name (assoc (meta name) :doc doc)) ~init)))It does allow a redefine, binding, or set! to an equal value mainly as an artifact of its implementation, but also because such a "change" would be harmless to the semantics of it being constant.
user=> (defconst pi (* 4 (Math/atan 1))) #'user/pi user=> pi 3.141592653589793 user=> (binding [pi 3] (prn pi))java.lang.IllegalStateException: Invalid reference state (NO_SOURCE_FILE:0)
user=> (binding [pi pi] (prn pi)) 3.141592653589793 nil user=> (binding [pi pi] (set! pi 3))java.lang.IllegalStateException: Invalid reference state (NO_SOURCE_FILE:0)
user=> (defconst pi 3)java.lang.IllegalStateException: Invalid reference state (NO_SOURCE_FILE:7)
user=> (def pi 3)java.lang.IllegalStateException: Invalid reference state (NO_SOURCE_FILE:10)
user=> (defconst pi (* 4 (Math/atan 1))) #'user/piI'd appreciate hearing any suggestions for improvement or other feedback.
--Steve
smime.p7s
Description: S/MIME cryptographic signature