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

I'd appreciate hearing any suggestions for improvement or other feedback.

--Steve

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to