Fork me on GitHub
#clojure-spec
<
2016-12-02
>
stathissideris13:12:31

@alexmiller destructuring like that throws an exception: (let [{::stats/keys [foo bar]} {::stats/foo 2}] foo)

stathissideris13:12:56

:stats/keys works, but that’s not what I meant

stathissideris13:12:36

because I have this in my require [spec-provider.stats :as stats]

dergutemoritz13:12:55

@stathissideris That should work AFAICT. What's the exception you get?

stathissideris13:12:19

spec-provider.trace> (let [{::stats/keys [foo bar]} {::stats/foo 2}] foo)
ExceptionInfo Call to clojure.core/let did not conform to spec:
In: [0 0] val: #:spec-provider.stats{:keys [foo bar]} fails spec: :clojure.core.specs/local-name at: [:args :bindings :binding :sym] predicate: simple-symbol?
In: [0 0 0] val: ([:spec-provider.stats/keys [foo bar]]) fails spec: :clojure.core.specs/seq-binding-form at: [:args :bindings :binding :seq] predicate: (cat :elems (* :clojure.core.specs/binding-form) :rest (? (cat :amp #{(quote &)} :form :clojure.core.specs/binding-form)) :as (? (cat :as #{:as} :sym :clojure.core.specs/local-name))),  Extra input
In: [0 0 :spec-provider.stats/keys] val: [foo bar] fails spec: :spec-provider.stats/keys at: [:args :bindings :binding :map :spec-provider.stats/keys :clojure.spec/pred] predicate: map?
In: [0 0 :spec-provider.stats/keys] val: [foo bar] fails spec: :spec-provider.stats/keys at: [:args :bindings :binding :map :spec-provider.stats/keys :clojure.spec/nil] predicate: nil?
:clojure.spec/args  ([#:spec-provider.stats{:keys [foo bar]} #:spec-provider.stats{:foo 2}] foo)
  clojure.core/ex-info (core.clj:4725)

stathissideris13:12:02

I’m on clojure 1.9.0-alpha14

bronsa13:12:46

I can't repro:

user=> (let [{::stats/keys [foo bar]} {::stats/foo 2}] foo)
2

dergutemoritz14:12:47

Yeah, same here. Something must be off in your namespace @stathissideris

stathissideris14:12:41

weird, thanks for trying @bronsa and @dergutemoritz

dergutemoritz14:12:15

@stathissideris You're welcome! If all else fails, try rebooting the REPL 😉

stathissideris14:12:50

REPL reboot didn’t help

stathissideris14:12:59

I think I’ll try in a fresh project

bronsa14:12:10

try *clojure-version* to confirm you're on alpha14?

bronsa14:12:17

@stathissideris hmm, do you have a ::stats/keys spec by any chance?

dergutemoritz14:12:01

That'd be nasty

bronsa14:12:33

yeah i can reproduce a similar exception by defining a dummy ::stats/keys spec

bronsa14:12:24

interesting, not sure if this was intentional but one can do this:

user=> (require '[clojure.spec :as s])
nil
user=> (s/def ::keys (s/coll-of '#{foo bar} :kind vector?))
:user/keys
user=> (let [{::keys [foo]} {}])
nil
user=> (let [{::keys [baz]} {}])
ExceptionInfo Call to clojure.core/let did not conform to spec:
In: [0 0] val: #:user{:keys [baz]} fails spec: :clojure.core.specs/local-name at: [:args :bindings :binding :sym] predicate: simple-symbol?
In: [0 0 0] val: ([:user/keys [baz]]) fails spec: :clojure.core.specs/seq-binding-form at: [:args :bindings :binding :seq] predicate: (cat :elems (* :clojure.core.specs/binding-form) :rest (? (cat :amp #{(quote &)} :form :clojure.core.specs/binding-form)) :as (? (cat :as #{:as} :sym :clojure.core.specs/local-name))),  Extra input
In: [0 0 :user/keys 0] val: baz fails spec: :user/keys at: [:args :bindings :binding :map :user/keys] predicate: (quote #{bar foo})
:clojure.spec/args  ([#:user{:keys [baz]} {}])
  clojure.core/ex-info (core.clj:4725)

bronsa14:12:29

if intentional, your issue is not a bug, otherwise I'd say it's a spec/`:clojure.core.spec/ns-keys` bug

stathissideris14:12:55

@bronsa OH! yes, I do have a ::stats/keys spec

stathissideris14:12:07

it doesn’t have to be called that, but it was the most natural name for what I’m doing

bronsa14:12:52

yeah I'm looking at the bindings spec and I don't think that's intentional behaviour

bronsa14:12:04

yeah looks like a bug with s/keys :opt-un

bronsa14:12:10

minimal repro:

user=> (s/def ::foo nil?)
:user/foo
user=> (s/def ::bar (s/keys :opt-un [::foo]))
:user/bar
user=> (s/valid? ::bar {:a/foo 1})
true
user=> (s/def :a/foo nil?)
:a/foo
user=> (s/valid? ::bar {:a/foo 1})
false

Alex Miller (Clojure team)14:12:42

You need to redef bar for that to take effect

Alex Miller (Clojure team)14:12:52

Specs are lazily compiled on use

dergutemoritz14:12:00

Note that bit from the s/keys docstring: "In addition, the values of all namespace-qualified keys will be validated (and possibly destructured) by any registered specs."

bronsa14:12:23

@dergutemoritz ah, then it's not a bug :)

bronsa14:12:19

leads to surprising results tho

dergutemoritz14:12:19

I think this is unrelated to the keys destructuring issue @stathissideris ran into

bronsa14:12:42

@dergutemoritz no, that's the same issue @stathissideris is having

Alex Miller (Clojure team)14:12:58

There are some weird corners with unqualified keys

dergutemoritz14:12:01

OK then I didn't get the connection, yet 🙂

bronsa14:12:30

the let binding destructuring specs are defined in terms of s/keys, which is why he's getting ::stats/keys validated against his ::stats/keys spec

Alex Miller (Clojure team)14:12:59

Yeah, that's pretty subtle :)

dergutemoritz14:12:21

I wonder if this is intended behavior in this particular situation, though 🙂

bronsa14:12:30

it feels a bit weird that that happens purely because of how those specs are defined (i.e. it depends on an implementation detail)

Alex Miller (Clojure team)14:12:12

We've talked about this a bit and I think this is a case where some effort could be taken to detect and warn (or maybe error)

bronsa14:12:54

realistically this means using ::keys or ::strs as spec is going to lead to those issues most of the times (unless your ::keys spec is literally a coll of simple-syms)

Alex Miller (Clojure team)14:12:00

It is in the ballpark of being open in your map specs or kwarg options

dergutemoritz14:12:01

An option to disable this behavior for particular keys specs might be useful, too

Alex Miller (Clojure team)14:12:32

That's already a pretty tricky hybrid map spec

bronsa14:12:56

cool, I'll open a ticket later to track this

dergutemoritz14:12:36

Great find everyone, I'm happy I probably won't have to run into this case myself some day and scratch my head in confusion 😄

bronsa15:12:48

attached a proposed solution

Alex Miller (Clojure team)15:12:26

We are absolutely not doing that

Alex Miller (Clojure team)15:12:19

I don't expect to make any adjustments to keys for this, but rather alter how the destructuring spec is written

bronsa15:12:26

fair enough