Skip to content

Commit

Permalink
:pre and :post conditions as metadata on arglist, or map following ar…
Browse files Browse the repository at this point in the history
…glist

conditions are predicate exprs in a vector
return value of fn is bound to % for :post
(defn foo [x y]
  {:pre [(even? x) (< x y)]
   :post [(> % 3)]}
  (* x y))
add *assert*, default true, when not true asserts are no-ops
*assert* is bound in repl
  • Loading branch information
richhickey committed Jun 24, 2009
1 parent ff26acc commit 0ac4828
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
28 changes: 23 additions & 5 deletions src/clj/clojure/core.clj
Expand Up @@ -2607,7 +2607,7 @@
(even? (count bindings)) "an even number of forms in binding vector")
`(let* ~(destructure bindings) ~@body))

;redefine fn with destructuring
;redefine fn with destructuring and pre/post conditions
(defmacro fn
"(fn name? [params* ] exprs*)
(fn name? ([params* ] exprs*)+)
Expand All @@ -2623,9 +2623,26 @@
sigs (if name (next sigs) sigs)
sigs (if (vector? (first sigs)) (list sigs) sigs)
psig (fn [sig]
(let [[params & body] sig]
(let [[params & body] sig
conds (when (and (next body) (map? (first body)))
(first body))
body (if conds (next body) body)
conds (or conds ^params)
pre (:pre conds)
post (:post conds)
body (if post
`((let [~'% ~(if (< 1 (count body))
`(do ~@body)
(first body))]
~@(map (fn [c] `(assert ~c)) post)
~'%))
body)
body (if pre
(concat (map (fn [c] `(assert ~c)) pre)
body)
body)]
(if (every? symbol? params)
sig
(cons params body)
(loop [params params
new-params []
lets []]
Expand Down Expand Up @@ -2794,8 +2811,9 @@
"Evaluates expr and throws an exception if it does not evaluate to
logical true."
[x]
`(when-not ~x
(throw (new Exception (str "Assert failed: " (pr-str '~x))))))
(when *assert*
`(when-not ~x
(throw (new Exception (str "Assert failed: " (pr-str '~x)))))))

(defn test
"test [v] finds fn at key :test in var metadata and calls it,
Expand Down
1 change: 1 addition & 0 deletions src/clj/clojure/main.clj
Expand Up @@ -27,6 +27,7 @@
*print-level* *print-level*
*compile-path* (System/getProperty "clojure.compile.path" "classes")
*command-line-args* *command-line-args*
*assert* *assert*
*1 nil
*2 nil
*3 nil
Expand Down
1 change: 1 addition & 0 deletions src/jvm/clojure/lang/RT.java
Expand Up @@ -179,6 +179,7 @@ public class RT{
final static Keyword TAG_KEY = Keyword.intern(null, "tag");
final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.create("*read-eval*"), T);
final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.create("*assert*"), T);
final static public Var MACRO_META = Var.intern(CLOJURE_NS, Symbol.create("*macro-meta*"), null);
final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
static Keyword LINE_KEY = Keyword.intern(null, "line");
Expand Down

0 comments on commit 0ac4828

Please sign in to comment.