We're updating the issue view to help you get more done. 

Postcondition in defrecord: Compiler unable to resolve symbol %

Description

Clojure's postconditions[1] are a splendiferous, notationally
idiot-proof way to scrutinize a function's return value without
inadvertently causing it to return something else.

Functions (implementing protocols) for a record type may be defined in
its defrecord or with extend-type. In functions defined in
extend-type, postconditions work as expected. Therefore, it is a
surprise that functions defined in defrecord cannot use
postconditions.

Actually it appears defrecord sees a pre/postcondition map as ordinary
code, so the postcondition runs at the beginning of the function (not
the end) and the symbol % (for return value) is not bound.

The code below shows a protocol and two record types that implement
it. Type "One" has an in-the-defrecord function definition where the
postcondition does not compile. Type "Two" uses extend-type and the
postcondition works as expected.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 (defprotocol ITimesThree (x3 [a])) ;; defrecord with functions inside cannot use postconditions. (defrecord One [] ITimesThree (x3 [a] {:pre [(do (println "One x3 pre") 1)] ;; (works fine) :post [(do (println "One x3 post, %=" %) 1)] ;; Unable to resolve symbol: % in this context. ;; With % removed, it compiles but runs at start, not end. } (* 1 3))) ;; extend-type can add functions with postconditions to a record. (defrecord Two []) (extend-type Two ITimesThree (x3 [a] {:pre [(do (println "Two x3 pre") 1)] ;; (works fine) :post [(do (println "Two x3 post, %=" %) 1)] ;; (works fine) } (* 2 3))) (defn -main "Main" [] (println (x3 (->One))) (println (x3 (->Two))))

[1] http://clojure.org/special_forms, in the fn section.

Environment

None

Status

Assignee

Unassigned

Reporter

import

Labels

Approval

None

Patch

None

Affects versions

Release 1.6

Priority

Minor