speculative 2018-11-03

Other topic: I would say this is a blocking issue for speculative to upgrade to the new CLJS: https://github.com/slipset/speculative/blob/cljs-1.10.439/issues/callstack.cljs

(conj {:a 1} (java.util.HashMap. {:b 2}))

The messages after this seem quite promising.

I think it will be fun to collect the list of issues that were already found through the usage of speculative. If you still remember them, I’ll add them to a .md file 🙂

Not sure if you detected this one via the usage of speculative Mike: https://dev.clojure.org/jira/browse/CLJS-2945

When you want to upgrade to ClojureScript 1.10.439, Planck is ready. You can update these lines https://github.com/slipset/speculative/blob/master/.circleci/config.yml#L43-L44 to specify 2.19.0-debian-9.0

(Homebrew versions of Planck are in the queue; until then brew install --HEAD planck.)

@mfikes I’ll try in the cljs-1.10.439 branch in a minute

Planck made it through the homebrew and binaries are now available

Happy to open an issue for this question if that’s a better forum, but would you accept a PR that wraps popular predicates in a spec?

e.g. add (s/def ::fn ifn?) and then replace every instance of ifn? with ::ifn

The reason this would be useful is that it’s possible for other libs to put spec keywords into a registry and attach more info e.g. expound

Additionally, if spec ends up adding metadata, I’m guessing that will also be attached to the spec name https://dev.clojure.org/jira/browse/CLJ-2194

The downside would be a) an additional thing to remember when writing specs b) if this was non-idiomatic (not sure it is) then it could conflict with the goal of making it easy to convert “speculative” specs into “official” specs

the most concrete upside is that it would allow me to write code to present more beginner-friendly names for functions like ifn? and seqable? which can be pretty opaque if you’re just getting started

I’ve already done this for pred, to indicate that the ifn in question should be a predicate.

@bbrinck there are already some examples of that. yesterday I added ::map-entry

Cool, so it’d be OK if I did a PR that extended that to, say, ifn? and seqable? among others?

Think so. I was contemplating a utils or predicates namespace, but maybe that’s premature.

Ok, well I’m happy to start a PR and we can adjust as necessary, as long as the general approach is consistent w the style so far. Thanks!

I’m going to create an issue with this, mostly because then there is something to link to

About CLJS-2956. This is really a nasty problem in CLJS since a lot of spec code uses e.g. = which causes = instrumenting to be in a terribly high callstack, e.g. I measured 473 nestings.

Possible directions: 1) Count the nestings in spec-checking-fn, if it’s a core fn we’re running and the nesting is too high, then call the raw function. I didn’t get this to work properly (yet) and it’s a hack only to get core spec’ing to work. 2) Use wrappers and pass them with :replace:

(defn =-replace
  ([_] true)
  ([x y] (= x y))
  ([x & args]
   (apply = x args)))

(defn =-test []
  (stest/instrument `= {:replace {`= `=-replace}})
  (println "yo")
  (= 1 1))

With 2 we lose the ability to core self-checking, but this may even what we want in speculative, since then the performance loss of instrumenting isn’t that big. Maybe these replace wrappers could be automatically generated.

Scratch that, it also doesn’t work, unless you can get to the raw function in the wrapper.

LOL, even getting to the raw function doesn’t help here.

(defn raw []
  (:raw (get @@#'cljs.spec.test.alpha/instrumented-vars `=)))

(s/fdef clojure.core/=
  :args (s/+ any?)
  :ret boolean?)

(defn =-replace
  ([_] true)
  ([x y] ((raw) x y))
  ([x & args]
   (apply (raw) x args)))

(defn wrong-call []
  (= "a" "b"))

(t/deftest =-test []
  (stest/instrument `= {:replace {`= `=-replace}})
  (println "yo")
  (= 1 1)
  (wrong-call))
Spec now calls =-replace internally where it used to call =, so same loop

Hah:

user=> (defn map?* [m] #?(:clj (instance? java.util.Map m) :cljs (map? m)))
#'user/map?*
user=> (merge {:a 1} (java.util.HashMap. {:b 2}))
{:a 1, :b 2}
user=> (associative? (java.util.HashMap. {:b 2})) ;; false
See: https://github.com/slipset/speculative/issues/70#issuecomment-435565720