views:

60

answers:

1

In the documentation for Clojure special forms (http://clojure.org/special_forms) the example for :pre and :post looks like this:

(defn constrained-sqr [x]
    {:pre  [(pos? x)]
     :post [(> % 16), (< % 225)]}
    (* x x))

How can Clojure tell if the map containing the meta-data is not the definition of the function? Shouldn't the meta-data precede the params vector? According to the documentation for defn (http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/defn), the syntax is

(defn name doc-string? attr-map? [params*] body)

with the attr-map? before the params vector. Isn't this more correct:

(defn constrained-sqr
    {:pre  [(pos? x)]
     :post [(> % 16), (< % 225)]}
    [x]
    (* x x))

Should I file a bug report or am I misreading this?

Sorry to pick nits.

+4  A: 

The map has to follow the argument vector because it depends on the arguments. And you can have multiple function bodies with different arities. The disambiguation is pretty simple: is the map the only thing in the body, it's the return value. If there was something else following it, the map would be thrown away. Then add it to the metadata. This is a very straight-forward and pretty simple heuristic which shouldn't clash with any production code.

kotarak
@kotarak: Is the documentation for `defn` wrong?
Ralph
@Ralph: no. The `defn` docs talk about the metadata of the function (actually: the Var containing the function). The conditions go to the metadata of the argument vector, not that of the function. As I said: the conditions depend on the arguments. It doesn't make sense to attach them to the function itself.
kotarak
@kotarak: Ahh! I see now. The `:pre` and `:post` are pre- and post-conditions on the value of `x`. Of course, they have to follow.
Ralph
@Ralph: Exactly. Consider this (hypothetical): `(defn foo {:pre [(pos? y)]} ([x] ...) ([x y] ...))` What happens if I call `(foo 1)`?
kotarak