Fork me on GitHub
#clojure-spec
<
2016-11-11
>
bbloom00:11:20

i just ran in to a situtation where (s? any?) matched the individual characters of a string

bbloom00:11:36

which i guess is not incorrect, but it’s certainly not what i expected 😕

bbloom00:11:56

what’s the best way to treat strings as scalars?

bbloom00:11:47

oh - no maybe something else has gone wrong

bbloom00:11:04

nevermind...

joshkh11:11:32

noobie question here. can spec be used to force a map into a particular shape? specifically, i'd like to drop all keys in a function's argument that aren't defined in :req-un/:opt-un

yonatanel13:11:43

@joshkh Just yesterday I learned about conformer. Maybe it will help you.

Alex Miller (Clojure team)13:11:20

@joshkh not much in spec that will help you (beyond using a conformer that calls select-keys or whatever way you'd do it without spec)

joshkh13:11:21

i read about conform but that appeared to return the original data if it conforms, or ::invalid if it doesn't. somehow i missed conformer. thanks 🙂

Alex Miller (Clojure team)13:11:57

there is an extension to keys that we've talked about that might help eventually

joshkh13:11:00

ah, okay. it's not a show stopper for me. i can easily select-keys on the map that's passed to my function. i was just wondering if there was a way to leverage my already written specs.

sophiago17:11:48

wondering if i can get some quick input, which might be no better than "just give it a shot incrementally, it's not all or nothing," and @alexmiller you might be well-suited to answer this if time permits: i wasn't paying attention to spec until i saw rich's sale's pitch (so to speak) last night and a lightbulb click re: debugging that symbolic algebra library with the custom numeric tower you looked at a while ago. he made several points that applied well to it: leveraging dynamic typing rather than out of laziness and accountability to stakeholders, the latter i couldn't really claim from having it "working fine" on its own as a library and with a couple clones and then breaking when i myself wrote the edge case that uses it with a library of lazy-seqs. to cut to the chase, i had to table the project and now and am weighing the time commitment of beginning to mark it up with spec vs. circling back to debug traditionally (possibly having to handroll my dynamic dispatch excluding the problem types as in math.numeric-tower). asking because you may vaguely remember the code i think it may be an ideal case because lazy-seqs both expose edge-cases in typing and are a nightmare to debug manually plus given the numeric tower is built with protocols i'm wondering how much that could cut down on my time commitment in writing tests. but then again, i'm not even sure if it would make sense to write the tests out of context in the library of making use of the library that broke it just to get the spec/explain data on it. apologies for the length, but any general advice for using spec to debug edge cases in custom typing would likely be useful given where i'm starting from. thanks!

Alex Miller (Clojure team)17:11:28

spec can certainly be helpful in debugging

Alex Miller (Clojure team)17:11:16

I’m working on a project right now where I have spec’ed most of the fns and run with instrument on while working at the repl and it’s been a huge time-saver to discover immediately when something doesn’t align

Alex Miller (Clojure team)17:11:08

(and actually writing the specs of course clarified thinking and design significantly)

Alex Miller (Clojure team)17:11:31

it’s impossible for me to judge how the effort involved in writing the specs compares with other debugging approaches for your particular problem

sophiago17:11:56

yeah, obviously i knew there was no answer to that question. and it's an incremental thing so i just try it out if i want

Alex Miller (Clojure team)17:11:59

however, the idea with spec is that if you do take the effort to write the specs, you can reap many benefits from it

Alex Miller (Clojure team)17:11:09

yes, it’s not all or nothing

Alex Miller (Clojure team)17:11:18

I’d start at the simplest, most basic functions

Alex Miller (Clojure team)17:11:36

try check to see if it flushes out any bugs at that layer

sophiago17:11:37

but more, advice on going that route given i've already exposed the bugs and the particular situation?

sophiago17:11:18

i guess the first question is whether to spec it at the level of the library that broke it or the broken library?

Alex Miller (Clojure team)17:11:56

but that’s just my intuition

sophiago17:11:59

but i know sort of what tests to write i suppose

sophiago17:11:55

like if i know essentially creating rationals using convolution (simplifying things a bit) seems to be where it's broken then i can spec it around that, but inside the typing library

sophiago17:11:43

i suppose mainly to separate the aspects of recursive functions and lazy-seqs from the actual type conversion causing the bugs and then get that spec/explain data on those cases

sophiago17:11:03

then hopefully approach similar libraries this way from the ground up going forward. it's true how we don't use unit tests, but also...a library isn't "working fine" just because you tested it manually in the repl on its own

sophiago17:11:01

(i may have another one to spec out too...good thing he made the learning curve seem slight. once he got to regex i was like, hmm benefits surely outweigh costs for me

sophiago17:11:14

i guess i'll come back after diving in, but one thing that comes to mind initially is whether i could use it to test for casting to java numerical types. i can't remember the syntax for one talk, but i have an exact idea of which ones are safe and which are causing the problems and i know you currently just have int? and float? for colls. i assume that must be extensible somehow, though

sophiago17:11:39

actually maybe that's enough? i'd have to check the source. but if i can say (s/cat (s/and [int? float?] )) or something like that and have it return false for rations and BigInts that would satisfy my contract

Alex Miller (Clojure team)17:11:24

they’re just functions - use any predicate you like

Alex Miller (Clojure team)17:11:32

check precisely what they mean though

Alex Miller (Clojure team)17:11:48

int? is satisfied by any fixed precision Java integer type (byte, short, int, long)

Alex Miller (Clojure team)17:11:02

float? is a fixed precision floating point (float, double)

Alex Miller (Clojure team)17:11:03

syntax would be like (s/cat :num (s/and int? float?))

sophiago17:11:17

sounds perfect then

Alex Miller (Clojure team)17:11:30

but you could pull the combo out into a separate spec too: (s/def ::fixed-num (s/and int? float?))

sophiago17:11:36

by nature your two specific numerical predicates exclude all the yucky java stuff

Alex Miller (Clojure team)17:11:45

then just (s/cat :num ::fixed-num)

Alex Miller (Clojure team)17:11:12

I assume yucky == arbitrary precision? :)

sophiago17:11:29

ratios, BigInts, BigDecimals

sophiago17:11:17

don't really have problems with the last one in this case, but the first two i would have excluded in diy dynamic dispatch

sophiago17:11:45

much of the point of having my own ratios was preventing overflow. the canonical power series code in haskell overrides their division for that reason as well

sophiago17:11:09

like gcd to 1 == 1N ???

sophiago17:11:45

and when you said overriding core math was "not so easy" subtyping was my problem having done it well before you made that statement. i suspect this leads into issues with subtyping, but then...hard to tell when everything is elegant yet opaque...hence s/explain