
Clojure 1.9 is now available - myth_drannon
http://blog.cognitect.com/blog/clojure19
======
escherize
Yes! With this release clojure.spec is ready to go (tm).

It adds a ton to Clojure(script), including better error messages (yes!),
data-structure shape declarations, generation of data, writing quickcheck
(generative) tests for a function by just describing the args and return
values of functions, and more.

~~~
karma_fountain
Yes, but I'm confused. The website still says specs still in alpha so whats
the deal? Is the spec api now stable?

~~~
tensor
Spec is still alpha as far as I'm aware. They decided to break spec off into
it's own library because it was holding up the release of 1.9.

~~~
puredanger
The API is still subject to change (alpha) but those changes are not expected
to be dramatic at this point.

~~~
roenxi
I'm looking forward to hearing a long-form rational of the :args :ret :fn
function instrumenting decisions, and seeing if the devs see it as an easy
choice or up for debate.

It feels really uncomfortable declaring a full spec for a function &
instrumenting it, then getting feedback if the args don't conform to spec but
Clojure being A-OK if the return value doesn't.

I understand well that in theory the functioning of a function can be fully
checked in a proactive test framework, but the process for testing return
values is way clunkier and less fun than testing argument values. It just
seems weird that the function has a spec, the function doesn't conform and
Clojure doesn't seem to be bothered.

I can see it will only be a matter of days until I have Orchestra installed
for all my projects.

~~~
int_19h
I'm not familiar with Spec, but what you're describing sounds like enforcing
preconditions but not postconditions by default, which is what most DbC
frameworks (or languages with intrinsic support) normally do. The idea being
that most of the time, you're running library code, and you want to validate
what you're passing in, but you trust it to do the right thing for any input
that is valid.

~~~
coinme
That’s fine, and makes sense, but without hacks, it is not possible to turn on
ret checking in your tests that are not generative tests - so no post
condition checks in the rest of your test suite.

I believe this is a missed opportunity to find bugs.

------
thom
I'm disappointed that spec didn't get beyond alpha for this release. This
worries me a little just because in the past a lot of stuff in Clojure
releases has felt abandoned after a while - transducers were new in 1.8, but
couldn't use the parallelism of 1.7's reducers (do we use them still?!)
because of the way stateful transducers worked. I don't see this having been
worked upon for this release.

As it is, spec is pretty slow, and the implementation is a massive black box,
with a ton of `(case op...)` on the inside making it almost impossible to
extend in any sensible way for the moment. Beyond that I'm still really not
clear on what the workflow with spec is supposed to be. I just don't verify
code in the repl and then move on with my life, and there's no clear guidance
on what a productive developer workflow for this stuff is. It doesn't help
when every example of generative testing I see online omits the bit where you
actually check a function does what it's supposed to.

Anyway, love Clojure still, but in a way it feels like an ongoing dialogue
that's over my head, rather than a programming language.

~~~
puredanger
There have been things that were alpha parts of Clojure for years in the past.
They were eventually finalized or in a few cases deprecated. Given that few
people try alpha software, it's better to release and let people use it while
the work is finished. I have no doubts that spec will finish and leave alpha.

spec is one of the fastest libraries available for validation
([http://muhuk.github.io/validation-
benchmark/](http://muhuk.github.io/validation-benchmark/)). spec is not
designed for extension by making new kinds of spec. It's designed to utilize
any predicate function on the bottom and by combination from the pieces
available. By analogy, is LEGO bad because it's hard to make your own bricks?
That's just not how you use it.

There are some known problems that make generation slow (mostly having things
that grow too quickly in combination). One known problem was fixed in the late
stages before release and we will continue to work on the sizing issues.

There is more to the generative testing story that has not yet surfaced. We've
got another whole project related to this that is still a work in progress.
Even without that, I think there is a lot of value to be had in spec right
now.

------
disease
Is clojure.spec a replacement for static typing? I ask because I've taken a
look at clojure in the past and generally like what I see, but after moving
from JavaScript to TypeScript at work I don't think I can ever return to a
dynamically typed language again. Types are just priceless when refactoring,
integrating someone else's code with your own or just exploring new libraries
or APIs.

~~~
tensor
It addresses similar problems as static typing, yes, but it's not a compile
time check. Instead, it's an optional runtime check. The idea is to use it
during testing and development, and have it be disabled during production.

~~~
jeremiep
Its also great at validating data!

We're running some of our specs in production to enforce guarantees on data
coming in and out of the app :)

~~~
misterbowfinger
Yup, specs can be used at runtime as well. Very helpful to validate data, or
perhaps a set of business rules. Insures the spec you use to test is the same
logic you use at runtime.

~~~
always_good
>specs can be used at runtime as well.

What do you mean "as well"? I thought it was only a runtime check at all.

~~~
ambulancechaser
i think they're talking about production run time versus development runtime.
think of it as turning asserts off on production builds. but spec can conform
data and explain the reason for non-conformance so some might leave some spec
in production for logging, messages, etc.

~~~
misterbowfinger
^^ this, using spec at run time in your actual application logic

------
_sdegutis
Why focus on command line tools? There's already Leiningen which does an
amazing job, and Boot for the few use-cases Leiningen doesn't take care of.
Creating another CLI seems very strange.

~~~
_halgari
Well, for the first time since the langauge was created you can now do `brew
install clojure`, and then `clj` on the commandline and get a repl. I would
have loved something that painless when I was learning Clojure.

~~~
_sdegutis
Leiningen has been incredibly painless:

    
    
        $ brew install leiningen
        $ lein repl
    

That's literally all it took.

~~~
systems
I agree, but it does take a while to figure out that leiningen exist

And then you learn that not everyone use leiningen ... and things become a bit
more confusing than necessary for some people, especially beginners

~~~
_sdegutis
Sorry but this whole conversation is a stretch. Anyone who looks into Clojure
finds out about Leiningen. The official clojure.org even mentions it. No it's
more than a stretch, it's rationalizing.

~~~
puredanger
As I mentioned at length in my prior answer, this was not the primary driver.

------
Y_Y
Can anyone sell me on why I should use clojure over say, any of the other nice
Lisp-1s, given that I don't care about java.

~~~
neutronicus
Associative data structures (maps / dicts) are super first-class in Clojure,
in a way that they aren't in other Lisp-1's (at least from what I remember of
dabbling in Racket). There's a literal syntax for them. Keywords are functions
that you can call with a map as an argument. You can destructure them in `let`
bindings. And so on.

In my opinion, this turns out to be a pretty major win. Code is still data,
it's just that this data is a mix of lists, vectors, and maps, and now you can
type associative data structures into your code as easily as you can lists.
Hash tables in vanilla Common Lisp are a nightmare (there is a nice library
that at least gives a Clojure-y initialization option via Reader macro), and a
glance at the Racket documentation suggests the story there is probably not
much better.

Clojure code in the wild uses the destructuring on maps a lot like, e.g.
Haskell code uses pattern matching, and Spec is an interesting core library
aimed at allowing libraries to insist that keys be present in maps and so on.

Anyway, I had occasion to interact with some Common Lisp code I'd written
several years ago, and I was struck by how annoyed I was at it for not being
Clojure. Part of that is the Lisp-2 issue, but I also really missed how
lightweight and easy Clojure maps are, and how easy they are to use for
control flow. (I will say that Clojure's clunky recursion annoys me, but much
less than trying to deal with Hash Tables in CL)

Also, and I know you say you don't care about Java, but ... sometimes you have
to interact with some annoying outside system (like, a database or a web
browser), and there is a high-quality Java(Script) library that makes this
task trivial and lets you work on what you want!

~~~
flavio81
> _Hash tables in vanilla Common Lisp are a nightmare_

I seriously disagree with such a statement.

Also, i feel confused that a lisp being a Lisp-2 could be an "issue". Separate
namespaces for functions, symbols, classes, labels and so on is great, because
they dramatically simplify naming things, which is one very important task for
writing clean, readable, maintenable code.

~~~
threatofrain
After using a Lisp for awhile I've come to feel that privileged symbols
improves ability to mentally acquire some code.

It was an okay learning journey, but it left me hungering for an easier FP
language, and it also solidified my intuition that simple is both easy and
hard at the same time, and Lisp is simple.

------
billfruit
How is debugging support nowadays? Does it allow to spawn a repl at point of
exception and examine locals? Is the Emacs based tooling become more refined?

~~~
billburcham

      clojure.core.server/start-server
    

Will start a socket REPL at any point in your Clojure program.

Unravel is a terminal-based REPL client you can use to connect to that REPL:

[https://github.com/Unrepl/unravel](https://github.com/Unrepl/unravel)

Alternately, for a smooth interactive development experience, including the
ability to set breakpoints on lines, there is Cursive:

[https://github.com/cursive-ide/cursive](https://github.com/cursive-
ide/cursive)

Cursive is a plugin for IntelliJ. There's a free community edition of IntelliJ
that works great.

