Hacker News new | past | comments | ask | show | jobs | submit login

I think the instrumenting and generator stuff gets disproportionate attention. For me by far the biggest win from spec has been with parsing. This completely changes how you'd write a library that takes a data structure and parses it into something meaningful (for example, what hiccup does for html or what honeysql does for sql).

In the past, this required a lot of very ugly parsing code and manual error-checking. With spec, you write specs and call s/conform. If it failed, you get a nice error, especially if you pair it with expound. If it succeeded, you get a destructured value that is really easy to pull data out of. I've done this in a half dozen different libraries and i'm pretty sure i wouldn't have even written them without spec.




Totally agree with this.

I started playing with spec because of the idea of automated test generation, but the reality of it is that I use it as a super-charged validation library.

I think this emphasis actually does the library a disservice in that I see new users ask questions along the lines of "Should I use s/valid? to manually check inputs to my API"? The answer to that, in my usage, is "Yes! Of course!", but many people seem to think that they are using Spec wrong if they use it for something other than instrumentation and generation.


I remember doing just that - writing some ugly parsing code, thinking that I should be a good team member and add some specs for what I was doing, and when I tried calling conform... Oh, it did the parsing for me!


Yup, surprised the article doesn't mention parsing.

When writing complicated macros, Spec conforming is so useful!


and if you then combine s/conform with core.match, you can build really elegant code to traverse these structures.


Why not just pattern match immediately if you are going to bother with using core.match?


How would you pattern match with Clojure without using core.match? Do you mean using another library?

Edit: oh I understand what you mean, you were thinking of skipping the s/conform part, and use core.match directly. Personally, I consider spec an excellent library to describe the shape of data, and core.match allows for better describing the actions you want to take based upon that.

For example, with spec you can define a bunch of alternatives using s/or, and then use core.match to then easily traverse the results.

It’s more a matter of separation of concerns to me. I don’t use core.match for validation or describing shapes of data.


Do you have to adapt spec definition to core.match somehow? Is there a resource to read more how to use them together?


No you don't have to do anything.

Let's say I have something like

  (s/def :thespec (s/or :foo ::foo 
                        :bar ::bar))
I can then use it in conjunction with core.match like

  (match [(s/conform :thespec val)]
    [:foo x] (do-something-with x)
    [:bar y] (do-something-else-with y))
Which imho is an easier way to navigate these things.


can you "stream" conform ? for UI live input

so that "john mcallister" yields { :name "john" :lastname "mcallister" } but "john " would yield { :name "john" :lastname nil } (or :todo even)


You could call it on every input change, though I'd say Spec conforming is not the most performant parsing library in the world, so not sure if it be fast enough for running it on each input.


yeah that's why I was looking for a lazy / stream variant in case it wasn't already possible

/me goes to prolog


This is why languages like Ocaml are really nice to work with for this stuff.


Does OCaml have a good parsing DSL build in?


Yes, it's called Ocaml ;)


Could you elaborate on your point?


Ocaml's strong static typing with type inference and pattern-matching (with exhaustivity checking) suite this kind of work quite well, there's plenty of literature around for it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: