Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conform :ret into :fn #40

Merged
merged 2 commits into from
Feb 7, 2019
Merged

Conform :ret into :fn #40

merged 2 commits into from
Feb 7, 2019

Conversation

cjohansen
Copy link
Contributor

@cjohansen cjohansen commented Feb 1, 2019

Fixes #26

Some notes:

The spec docs says to ignore :fn in the case where either :args or :ret is missing, but Orchestra has opted to treat a missing :args as a failure. I initially intended to treat a missing :ret the same way, but was unable to write a failing test for it... It seems that even without specifying a :ret spec, the :ret spec is set to something anyway. I tried:

(defn func-no-ret-spec [meow]
  (Math/abs meow))
(s/fdef func-no-ret-spec
  :args (s/cat :meow number?)
  :fn (constantly true))

(deftest func-no-ret-spec-test
  (is (thrown? #?(:clj RuntimeException :cljs :default)
               (func-no-ret-spec -42))))

But this did not fail as expected. Inspecting the code (:ret spec) was set even though I didn't provide one. I don't know the Orchestra implementation well enough to deduct why.

(when-let [spec (:fn fn-spec)]
(if (nil? cargs)
(throw (no-args-spec v fn-spec))
(conform! v :fn spec {:ret ret :args cargs} ::s/fn)))
(conform! v :fn spec {:ret cret :args cargs} ::s/fn)))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this logic has an issue. In the case where no :fn is provided (and one is certainly not required), the :ret value will no longer be taken from the fn application. Instead, it will be nil because of the when-let.

We probably want something like this:

(let [; ...
      ret (.applyTo ^clojure.lang.IFn f args)
      cret (if-some [spec (:ret fn-spec)]
             (conform! v :ret spec ret ::s/ret)
             ret)]
  ; ...
  )

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my bad. Like I said, I initially treated the missing ret spec as an error, but was unable to verify it with a test. Added a safe-guard to ensure there is always a value there.

@borkdude
Copy link

borkdude commented Feb 4, 2019

NOTE: this bug in Orchestra became apparent by instrumenting map, filter, keep etc. of https://github.com/borkdude/speculative. E.g. the map spec is:

(s/fdef clojure.core/map
  :args (s/alt :transducer (s/cat :f ::ss/ifn)
               :seqable (s/cat :f ::ss/ifn :colls (s/+ ::ss/seqable)))
  :ret ::ss/seqable-or-transducer
  :fn (fn [{:keys [args ret]}]
        (= (key args) (key ret))))

I'm interested in a fix for this bug, so I can use Orchestra to validate the ret and fn specs of speculative by instrumenting larger codebases.

@jeaye jeaye merged commit 2b0904c into jeaye:master Feb 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants