
Clojure 1.6 released - Morgawr
https://github.com/clojure/clojure/blob/master/changes.md
======
beat
I've switched my own back end codebase to Clojure. It's just a joy to work
with. Building REST with Liberator is a revelation. It's so easy to _reason_
about what the code is doing, and immutability leads to far fewer bugs. Not
missing objects, not at all.

The stock concern for businesses building with Clojure is the lack of talent
and industry acceptance. I have a different angle. I figure that when I'm
ready to start hiring other developers, I'll only be hiring developers
sophisticated enough to see the benefits of using Clojure over
Java/Ruby/Python/etc - and then I'll have the draw of letting them work in the
best tools, not making them compromise so it's easier for management to hire
less serious programmers.

~~~
platz
Is it still so easy to maintain Clojure code given it's lack of types?

(I know about Typed Clojure; it doesn't seem to have won the hearts of all
Clojurians)

(Or, do you just test the bejezus out of the thing?)

~~~
lkrubner
I add :pre and :post assertions to most of my functions, so I know the type of
everything coming in, and also what is returned. An example of a function that
saves a document to MongoDB:

(defn persist-this-item [item]

    
    
      {:pre [
    
             (map? item)
    
             (= (type (:item-name item)) java.lang.String)
    
             (= (type (:item-type item)) java.lang.String)
    
             (if (:created-at item)
    
               (= (type (:created-at item)) 

org.joda.time.DateTime)

    
    
               true)
    
             ]}
    
      (let [item (if (nil? (:created-at item))
    
                   (assoc item :created-at (tyme/current-time-as-datetime))
    
                   item)
    
            item (assoc item :updated-at (tyme/current-time-as-datetime))
    
            item (assoc item :_id (ObjectId.))]    
    
        (mc/insert "tma" item)))
    

So this function needs to be given some kind of map, and it needs to have 2
keys, :item-name and :item-type, and both of these need to be strings, and if
:created-at is already set, then it needs to be a Joda DateTime.

It's not accurate to say that Clojure has no types. It just gives you some
flexibility about how strict you want to be.

I find that Clojure strikes a perfect balance: its flexibility with types
allows me to easily integrate a lot of 3rd party tools without much work, but
when I need to I can be as strict as a I like with types.

Edit to add: wow, the code is ugly on Hacker News. Funny that this site
provides no tools for posting code snippets, given the subject.

~~~
thinkpad20
Maybe I'm misunderstanding, but it looks like every time these functions get
called, they're type checking their inputs and outputs? That seems like a
waste of resources. Why not just write unit tests that ensure that they will
always be called with the types you expect (or fail at an earlier step if
not)? Identify the places where there might be ambiguity in something's type
(e.g. when a JSON blob arrives, it might map a key to a list instead of a
dictionary, or if a function might return multiple types, etc), and use unit
testing to ensure that the type you expect will emerge from those places, or
else a failure will occur.

~~~
bad_user
Unit testing cannot prove the absence of bugs and shit happens in spite of
their presence. That's why I still value (good) static type systems. But
besides a good static type system that can prove certain properties about the
code (and I'm not talking about Java's type system here), you can also do
_design by contract_ [1], which is precisely what @lkrubner is doing and I
find that to be pretty cool.

Well, it would be cooler if the compiler could check those contracts at
compile-time and issue some helpful warnings, but at runtime they are still
valuable because the code will fail sooner rather than later. Plus you can
probably disable them completely, should you experience problems with
performance in production.

They also serve as documentation for other developers, documentation that
you're forced to keep in sync. This documentation is not about the actual
business logic, that ends up being laid out in tests, but rather about
interface specifications and invariants.

So there you have it - testing serves a different purpose.

[1]
[https://en.wikipedia.org/wiki/Design_by_contract](https://en.wikipedia.org/wiki/Design_by_contract)

~~~
thinkpad20
Nothing about what I was saying precludes the use of design-by-contract; in
fact, that's what I was advocating. You say that "at runtime [type assertions]
are still valuable because the code will fail sooner rather than later," which
is what I meant by identifying places where there is a possibility for the
wrong type to be used, and putting your assertions there. Sticking type
assertions on the inputs and outputs of every function you write would be
unnecessary, inefficient and horrible to read:

    
    
        def increment(n):
            assert isinstance(n, int) or isinstance(n, float)
            result = n + 1
            assert isinstance(result, type(n))
            return result
    

So as long as we can agree on that much, then we can agree that there is a
value to being judicious about where you should and shouldn't use type
assertions.

By the way I'm a fan of static typing as well, although I see value in dynamic
languages too. And I definitely acknowledge the limitations of unit testing,
although from a practical point of view, a comprehensive set of unit and
functional tests is usually robust enough. And, of course, type systems don't
make any guarantees against _logic_ errors. :)

~~~
bad_user
Well, I misunderstood your point then.

On your example, you're of course right. I'm also not a fan of checking the
actual type in a dynamic language, since it defeats the purpose of it being
dynamic. I like assertions that are more useful than that, like:

    
    
        def sqrt(x):
            assert x >= 0, "only defined for positive numbers"
    
            last_guess = x / 2.0
            while True:
                guess = (last_guess + x / last_guess) / 2
                if abs(guess - last_guess) < .000001: 
                    return guess
                last_guess = guess
    

Now clearly this helps, since it aids in readability (this function is defined
for positive numbers only) and if you call it with a negative number, it will
loop forever.

------
BadassFractal
Been using Clojure in production for our API (core of the system) for close to
a year now, it's been a very interesting ride.

Like many others pointed out, I do wish I had types though: refactoring is a
giant pain in the ass even at our modest codebase's scale (10-15k lines),
requiring endless UTs to make sure everything's still sane. Dynamic typing is
fun for the simpler cases, but as soon as you go into trickier computations
like crunching analytics data, you continuously run into run-time type
mismatches that take forever to correctly pinpoint. Also having to
continuously keep in your head just what exactly you're threading through
functions is a pain and requires a lot of mental overhead.

The JVM also doesn't seem to bring much of a benefit to the table, considering
that we only ever deploy onto 64bit Ubuntu 12.04, so there's not really a big
need for portability.

The best part has been how fun it is to work in clojure and the community
around #clojure channel with so many of its freakishly smart people. People on
there seem to generally be very willing to help explain something if you're
being obtuse.

------
sdegutis
We've been using Clojure for our web app at work since day 1. The biggest gain
by far is the referential transparency[1] built into the core libraries, which
has also been closely adhered to by nearly all third party libraries (with
only a few unfortunate outliers). I cannot emphasize enough just how much of a
gain this has been.

[1]:
[http://en.wikipedia.org/wiki/Referential_transparency_(compu...](http://en.wikipedia.org/wiki/Referential_transparency_\(computer_science\))

~~~
platz
Any posts which explain how the referential transparency built into the core
libraries helps? My understanding is that Clojure is impure, so a "partially
referentially transparent" design is interesting to me.

Or are you just referring to the fact that the core data structures are
immutable?

~~~
adambard
Clojure strongly encourages referential transparency (e.g. immutable data
structures), but doesn't demand it (e.g. STM). The convention is simply to
mark any function with side-effects with a !, which almost all external
libraries follow.

Without the !, you can have some confidence that a given function is pure,
since pure functions are sort of the "default".

~~~
platz
Ruby follows this convention too, I believe; but probably to a lesser extent
because it's core types aren't immutable

------
pi-rat
Not sure if I like the 'some?' operation. It's short for (not (nil? x)).. And
has nothing to do with 'every?' -which checks if every element of a collection
matches a predicate - ex (every? odd? [1 3 5])

To check if some elements match you need to use (some odd? [2 3 4]) - note the
lack of '?'

Bet it will confuse people.

~~~
emiljbs
I'd love to hear the reasoning behind that choice if it's Rich Hickey that did
it, since it's called some and every in Common Lisp and he's written a great
deal in that language.

~~~
puredanger
The names were chosen by Rich. Many choices were considered and they all had
pros and cons. The new some?/if-some/when-some functions follow the "not nil"
notion in "some->" (but break with the meaning in "some"). Naming is hard. :)

------
konradb
Absolutely loving Clojure. I typically hang out in java-land. I tested it out
on an annoying problem to scratch an itch and wow, I'm actually enjoying
programming again. I find myself looking forward to solving problems with
Clojure in a way I haven't for a long time.

------
grandalf
Some of the smartest code I've read lately has come from the Clojure
community. It's a great time to live in NYC.

~~~
segmondy
I'm in Detroit, and I'm not missing out on Clojure fun. Might miss out on
meetups, but everything is still accessible from the Internet, so I don't see
your point about NYC. With that said, a lot of different languages have
beautiful code, from C, ie Lua source, PHP Symfony, etc. With that said, I
love Clojure as well, and it's all because it's Lispy. :)

~~~
elwell
"i.e." means "that is"

"e.g." means "for example"

------
dj-wonk
Like many people on the mailing list, I've been using the Clojure 1.6 betas
and release candidates. Don't expect dazzling new features; rather, 1.6 is a
nice solid step forward.

~~~
Morgawr
As it should be, in my opinion :)

------
pjmlp
A nice pragmatic Lisp, might never use it at work, but it sure is fun to play
with.

Congratulations on the work.

~~~
TheSmoke
why wouldn't you ever use it at work?

~~~
dmix
Because it's rare to find companies using it. I'd love to write clojure, but
everyone wants me to write ruby or javascript.

~~~
adrianm
Really? I've gotten my fair share of recruiter emails looking for Clojure
work. I introduced Clojure into my last job quite easily as well. If you're
doing anything Java or JavaScript related, I've found it's pretty easy to get
Clojure in the door once people see what you can do with it.

~~~
tom_b
Interesting - where do you see these recruiter emails coming from, geography-
wise? I watch, say indeed.com, and see Clojure mentioned mostly as "nice to
have" mainly for what, on the surface, appear to be standard, enterprise Java
jobs.

------
mark_l_watson
Nice upgrade. I have used Clojure for several customer projects and some of my
own little projects like cookingspace.com and my-foc.us

Clojure is a very practical language and basically stays out of your way
during development.

------
thescrewdriver
A healthy language ecosystem on the JVM is a good thing, glad to see a new
Clojure release.

------
grn
I plan to learn Clojure this year. What online resources and books can you
recommend for learning the language and the tooling?

~~~
puredanger
Books - any of the intro Clojure books, they're all good. I prefer the OReilly
one but I think it's really a matter of preferred style.

Online - Clojure for the Brave and True, Clojure From the Ground Up are great
series. Or try the ClojureBridge curriculum
[https://github.com/ClojureBridge/curriculum](https://github.com/ClojureBridge/curriculum).

Practice problems - 4clojure, exercism.io, clojure koans

Editors - if you want to focus on Clojure not an editor, I'd suggest Nightcode
or Light Table. If you like IDEs I'd recommend IntelliJ w/ Cursive or Eclipse
Counterclockwise. If you already use Emacs, use CIDER. If you already use Vim,
use Fireplace.

------
craigching
Does anyone know where the Clojure roadmap is? I'm wondering what I can expect
in the next big release :)

Congrats on the release!

~~~
puredanger
Haven't started talking about it yet. :)

------
poofyleek
like the emacs org-mode pprint support. especially the example output claiming
the well deserved rock star status.

------
elwell
It's always hard get a sense of the actual usage presence of Clojure when I
spend so much time on HN, where Clojure is disproportionately represented.

~~~
puredanger
There are ~9000 people on the Clojure mailing list and ~8000 members of
Clojure meetups on Meetup.com. Hopefully those are useful and concrete
numbers.

~~~
elwell
Yet, essentially all the web application examples I've seen have been very
basic / boilerplate. Is Clojure not considered a good tool for complex web
apps?

~~~
grayrest
React was the missing link for sophisticated clojurescript web apps. The
Clojure community discovered it in December. Expect substantial web apps this
year. The largest open sourced example I'm aware of in this new wave of apps
is Omchaya [1] which isn't that large but shows how large apps could be
structured.

[1] [https://github.com/sgrove/omchaya/](https://github.com/sgrove/omchaya/)

