You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I am having some trouble coercing a heterogenous collection using coax.
If you have a look at the example below, the ip collection has three different types of values. I want to convert them to the vector defined in op. The transformation is simple, just convert every string to a keyword.
I have written two specs for illustration.
Here op conforms to spec-op. spec-ip is same as spec-op with keyword? replaced by string?.
It can be seen that ip conforms to spec-ip as expected. This illustrates that the spec is correct.
The problem arises when I try to coerce ip using spec-op. It is failing when trying to coerce the third entry in the vector i.e. ["f3" ["a1", "a2", "a3"]]. The conform accepts the input.
This seems to be a bug in coax because conform is working as expected but coerce is not working.
I kind of missed the notification about this one, sorry about that.
It's an ambiguity issue. I will have a look next week and fix it, but basically:
the or with :
:fn-with-arg (s/coll-of keyword?)
:fn-with-var-arg (s/tuple keyword? (s/coll-of keyword?))
coax tries the or specs in order, the first one modifying any value in the data is considered to be the one to be picked up, so it never reaches fn-with-var-arg. So coax decides to pick up fn-with-arg, modifies what it can to match keyword? and leaves the rest alone (as it does for anything else).
Until then you can workaround it by changing the order in the s/or and registering a custom coercer for fn-with-arg that will reject the value when it should:
(s/def::fn-with-var-arg-kw (s/tuple keyword? (s/coll-of keyword?)))
(s/def::fn-with-arg (s/coll-of keyword?))
(s/def::spec-op
(s/coll-of (s/or:fn keyword?
:fn-with-arg::fn-with-arg:fn-with-var-arg::fn-with-var-arg-kw)))
[...]
(c/coerce::spec-op ip
{:idents {::fn-with-arg
(fn [x _opts]
;; could also be a call to a spec
(if (and (coll? x)
(every? #(or (string? %)
(keyword? %))
x))
;; it matches we know for sure it's the a fn-with-arg, no more ambiguity, coercing is safe.
(c/coerce::fn-with-arg x)
;; otherwise it's invalid, the next `or` clause will be tried:exoscale.coax/invalid))}})
Not great but better than nothing until it gets fixed.
mpenet
changed the title
Coercion not working for tuple spec
s/or ambiguity with "un-ordered" or clauses
Dec 17, 2024
Hello,
I am having some trouble coercing a heterogenous collection using coax.
If you have a look at the example below, the
ip
collection has three different types of values. I want to convert them to the vector defined inop
. The transformation is simple, just convert every string to a keyword.I have written two specs for illustration.
Here
op
conforms tospec-op
.spec-ip
is same asspec-op
withkeyword?
replaced bystring?
.It can be seen that
ip
conforms tospec-ip
as expected. This illustrates that the spec is correct.The problem arises when I try to coerce
ip
usingspec-op
. It is failing when trying to coerce the third entry in the vector i.e.["f3" ["a1", "a2", "a3"]]
. The conform accepts the input.This seems to be a bug in coax because
conform
is working as expected butcoerce
is not working.The text was updated successfully, but these errors were encountered: