I am creating a function within a function in Clojure, to simulate Java's objects concept where my function person acts like a constructor. (Just to wrap my head around using this concept in Clojure.)
(defn person [name age]
(def p (fn [args & age]
case args
:set-name (person (first args) age)
:set-age (person age)
;; :get-name (person (first args))
;; :get-age ()
)))
But I am getting the following error :
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.core/case, compiling:(null:2:8)
def
inside another def
or defn
. Using def
is a global declaration and it should (nearly) always stand alone in the source file.See Clojure for the Brave & True for an intro online, or many good books like Getting Clojure
.
case
:Example:
(case args ...)
case
is really a special function designed primarily for Java object interop, and comes with some serious limitations (aka "optimizations"). It is nearly always better IMHO to use cond
.Example:
(cond
(= :set-name args) (person (first args) age)
(= :set-age args) (person age)
...)
One of the problems with case
is that it must be a compile-time literal. However, this is not obvious and there is no warning if you try to use something that doesn't fit the definition. Then, you just get a silent failure. This example looks like it should return "my vec"
, but it fails & returns "default"
:
; "The test-constants are not evaluated. They must be compile-time
; literals, and need not be quoted."
(let [myvec [1 2]]
(case myvec
[] "empty vec"
(vec '(1 2)) "my vec"
"default"))
;=> "default"
So using case
leaves a booby-trap ready to break your code without warning.