speculative

https://github.com/borkdude/speculative
borkdude 2018-11-03T06:58:25.002700Z

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

borkdude 2018-11-03T07:03:31.003300Z

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

borkdude 2018-11-03T08:42:12.003700Z

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

slipset 2018-11-03T09:32:41.004700Z

The messages after this seem quite promising.

borkdude 2018-11-03T12:24:23.006Z

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 🙂

borkdude 2018-11-03T12:25:57.006100Z

https://dev.clojure.org/jira/browse/CLJS-2956

borkdude 2018-11-03T12:48:24.006600Z

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

borkdude 2018-11-03T12:50:33.006800Z

and this one? https://dev.clojure.org/jira/browse/CLJS-2951

mfikes 2018-11-03T14:32:55.007900Z

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

mfikes 2018-11-03T14:36:21.008700Z

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

borkdude 2018-11-03T15:08:12.009600Z

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

mfikes 2018-11-03T17:36:50.010Z

Planck made it through the homebrew and binaries are now available

bbrinck 2018-11-03T21:55:10.011300Z

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?

bbrinck 2018-11-03T21:55:40.012100Z

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

bbrinck 2018-11-03T21:56:38.013400Z

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

bbrinck 2018-11-03T21:57:08.014Z

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

bbrinck 2018-11-03T21:59:44.016700Z

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

bbrinck 2018-11-03T22:00:39.017800Z

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

slipset 2018-11-03T22:06:12.018200Z

PR welcome!

slipset 2018-11-03T22:09:43.020200Z

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

borkdude 2018-11-03T22:23:03.021Z

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

borkdude 2018-11-03T22:24:48.022100Z

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.

borkdude 2018-11-03T22:26:19.023800Z

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))

borkdude 2018-11-03T22:30:10.024Z

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.

borkdude 2018-11-03T22:42:21.024600Z

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

bbrinck 2018-11-03T22:43:37.024700Z

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

borkdude 2018-11-03T22:47:12.024900Z

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

bbrinck 2018-11-03T22:48:21.026300Z

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!

borkdude 2018-11-03T22:50:26.027300Z

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

bbrinck 2018-11-03T23:38:32.028Z

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