
Why use Clojure? - iamtechaddict
http://www.paradiso.cc/why-use-clojure/
======
DigitalJack
The big lie wrt lines of code vs bugs is the kind if bugs.

What good is a single line of clojure vs 25 of golang if it takes 45 minutes
to get that line of clojure working. I might have more bugs in my golang but
the are trivial.

I've busted my ass on clojure for two years with various projects
(systemverilog parser/manipulator, CPAP data decoder interpreter visualizer).
I want to use clojure but I find myself dealing with awful error messages,
constantly breaking tooling (cider), and dealing with asinine constructions
all in the name of functional and programming directly in an AST.

I tried. I've read the awe inspiring posts about lisp from Graham and Fogus
and Raymond and of course R Hickey and Granger and Hagelberg and Stokke . I
think all these people are amazing!

After two years I have not gotten there. I can write reasonably sophisticated
applications, but the productivity is so low I feel like in programming in
Russian.

I got fed up with tree traversal the other day and said screw it. I turned
around and rewrote versions of my CPAP app in golang, and then CPP in d a day.
It took me weeks to get this done in clojure.

I couldn't get a binary parser framework to work except for the most trivial
case, so I wrote my own generic binary parser. I couldn't tell if seesaw made
swing better or worse. Actually I decides worse because at aleast with Java
interop I can tell what the hell is going on.

In CPP writing a binary parser was nearly as simple as defining a struct and
memcpy. God I live memcpy. You know how many years it's been since I wrote
CPP? Never. I've never written a line of CPP before and the rewrite was almost
pain free. The Makefile and understanding data alignment in struct a was the
hard part.

~~~
tieTYT
I can so related to this. Thank you for articulating the problem (I thought I
was just doing it wrong). To elaborate on what you're saying in pseudo code,
imagine writing this in algorithm in clojure:

    
    
        take a collection -> split by is-even? -> for each collection, sort ascending -> take the first of each collection
    

This is the level of abstraction I want to think about. But, when one of these
functions takes or returns something you don't expect, debugging the problem
usually took me 30 minutes. The error messages were very opaque to me.

I could never figure out a good work flow to debug these problems. I still
feel like there's something I'm doing wrong. People on IRC tell me you
eventually understand the errors better, they're just confusing at first. I
never got to that point though.

~~~
jonase
Am I missing something here or is the algorithm you describe simply: "Find the
smallest even and odd number in a set of numbers?" This shouldn't be hard to
do in any language.

~~~
tieTYT
That's exactly what it is and I agree. Clojure is awesome because you can
almost write the actual code just the pseudo code.

> But, when one of these functions takes or returns something you don't
> expect, debugging the problem usually took me 30 minutes. The error messages
> were very opaque to me.

~~~
markc
>you can almost write the actual code just the pseudo code.

Yes, often true. E.g. in this case:

    
    
      (->> [2 3 4 7 5 3 11 12 7] ;collection
         (group-by even?)        ;get a map of evens and odds
         vals                    ;get just the values
         (map sort)              ;sort them
         (map first))            ;first is smallest
    

(disclaimer: there's probably prettier ways to write this - I was just trying
to keep it simple)

I agree that there are sometimes inscrutable errors. For me it's often because
of a type conflict between a function and what it's operating on.

Example: I'm a little rusty and when I tried to quickly code the example above
I did this:

    
    
      (->> [2 7 5 3] (partition-by even?) vals)
    

And got:

    
    
      ClassCastException clojure.lang.Cons cannot be cast to java.util.Map$Entry  clojure.lang.APersistentMap$KeySeq.first (APersistentMap.java:152)
    

Doh! I wanted "group-by". And partition-by doesn't make a map! But why this
specific error? Frankly I'm not sure. I'd probably have to look at the source.
My sin of course was trying to compose operations in one go, rather than build
them up by baby steps in the REPL. I don't think the errors ever get that much
more readable, but you start to recognize the category of error you've made by
the type of error that's thrown.

Spending time on 4Clojure is very helpful to build your intuition for this.

~~~
glogla
You can make that somewhat more close to the correct computation, you don't
need to sort the lists, you just need min values.

    
    
      (->> [2 3 4 7 5 3 11 12 7]
           (group-by even?)
           vals
           (map #(apply min %)))</pre>
    

However, operation like this can be made much more readable if you actually
use variables like this:

    
    
      (defn min-even-odd [xs] 
        (let [evens (filter even? xs)
              odds (filter odd? xs)] 
           (list (apply min evens) (apply min odds))))
    
      (min-even-odd [2 3 4 7 5 3 11 12 7])
    

Which is a bit longer, but I think it makes more sense.

------
lkrubner
I feel like the "Why Use Clojure?" essay is a bit flawed. I feel like it
focuses too much on details so minor that I would regard them as trivial. I
would suggest that a much better answer to the question "Why use Clojure?"
could be found by reading Colin Steele's essays. When he became CTO at
Hotelicopter/RoomKey he was inheriting a vast system of PHP and Ruby. When
they re-wrote the system in Clojure, he had a very small team: only 4
programmers. That they were able to accomplish so much in a short amount of
time says a lot about the power of Clojure. These are 2 essays he wrote:

60,000% growth in 7 months using Clojure and AWS

[http://www.colinsteele.org/post/27929539434/60-000-growth-
in...](http://www.colinsteele.org/post/27929539434/60-000-growth-in-7-months-
using-clojure-and-aws)

Against the Grain: How We Built the Next Generation Online Travel Agency using
Amazon, Clojure, and a Comically Small Team

[http://www.colinsteele.org/post/23103789647/against-the-
grai...](http://www.colinsteele.org/post/23103789647/against-the-grain-aws-
clojure-startup)

At this point RoomKey is a lot bigger than Hipmunk.

~~~
sehugg
Those posts don't tell me much about Clojure, except that Ruby wasn't fast
enough and Java wasn't fun enough, and that the CTO digs Lisp. Doesn't give me
concrete reasons why I couldn't do the same with Java + Netty.

~~~
lkrubner
If you want a more detailed response, I posted a longer and more technical
answer in response to the recent post "Why functional programming?"

[https://news.ycombinator.com/item?id=6961033](https://news.ycombinator.com/item?id=6961033)

------
kohanz
The introduction has a reasonable premise, but I thought _Business Case No. 1_
doesn't do much to further the point. In fact, it reinforces the
academic/industry divide that is belabored in the intro.

Ask people who are working on "commercial" development how often they have to
implement a Fibonacci sequence or something similar. The example comes across
more like a neat party trick then something that would make itself useful on a
daily basis.

------
mpweiher
Not very convincing when the very first example is apples vs. oranges: the
java fib() code includes a main() driver with command line parsing and
printing of the result to stdout, which I don't see in the clojure version.

~~~
GhotiFish
also. I have absolutely _no_ idea how the first one even works.

fib-seq is not a defined token. wtf is going on here?

~~~
zcam
It's sloppy copy/paste work from
[http://en.wikibooks.org/wiki/Clojure_Programming/Examples/La...](http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci)

This post is quite poor imho, and I am a clojure developer (I do use it at
work as main language).

Maybe it's also because I don't find Midje appealing at all, or find a bit odd
the minimalism argument when talking about lighttable vs emacs. If you know
what you're doing with cider-mode (previously nrepl) on emacs there's no
reason at all to switch to lighttable, quite the opposite. LT is probably good
for newcomers, but for power users it's just not there yet (if ever).

Same goes for Marginalia, interesting and amusing, but I wouldn't use this for
real documentation.

------
kvtrew76557
Good question. Unlike most languages with which I am not yet familiar, Clojure
looks like Greek. Most languages are at least somewhat readable. Perhaps I
need to know Lisp to appreciate Clojure. Coming from a
Java/Scala/Ruby/Python/Haskell/Pascal/C# background. I can't make head or tail
of Clojure examples. It might as well be encrypted. To those who are using
Clojure, which previous languages enabled you to make sense of Clojure more
easily? Or was it something you learned from scratch?

~~~
coldtea
If you're really coming from a Haskell background I very much doubt that you
"can't make head or tail of Clojure examples. It might as well be encrypted.".

Except if you mean that you dabbled in Haskell, but are a
Java/Scala/Ruby/Python/Pascal/C# guy.

In any case, it takes no more than 1-2 days (from scratch) to get to
understand functional code. Remember that you weren't born able to understand
imperative code either. Just learn the (very basic) syntax rules, and the rest
is easy.

~~~
adrianm
This is so true - what interesting to me is that I have heard this sentiment
directly from friends and coworkers before several times. Upon further
prodding, it has been the case that their dealings Haskell were minor at best,
and are confusing the superficially similar syntax of Haskell with languages
they're used to, thereby giving them the idea they understand the code they're
reading. But more often than not they really don't understand it - the brain
is apparently adept at making us think we understand something we really don't
based on a superficial, usually structural similarity with an existing
knowledge domain we have.

I recall interviewing a potential hire who lauded his appreciation and
understanding of functional programming - and he really believed it. So I
asked him to explain to me what a closure was, and give me some examples of
ways you can exploit them in your code, practically. Pretty straightforward
question for someone who claims to understand the concepts of functional
programming.

Of course, I wouldn't be bringing this up if he was even remotely successful,
but I don't think this was a result of his presenting himself in a dishonest
manner. I think closures are subtle ideas; much like function application,
composition, and other ideas that seem familiar and easy to understand until
you are asked to apply them practically. That's when the gap between what you
think you know and what you actually know is borne for the world to see.

~~~
auggierose
Closures are nice, but you don't have to understand them in order to
understand functional programming ... Closures are more about how functional
programming languages are implemented.

~~~
adrianm
I find encapsulating mutable state within closures to be an indispensable and
practical tool I use in almost every (stateful) program I write.

------
lpolovets
I wrote an answer to this question on Quora a while ago:
[https://www.quora.com/Clojure/Why-would-someone-learn-
Clojur...](https://www.quora.com/Clojure/Why-would-someone-learn-
Clojure/answer/Leo-Polovets?share=1)

I think the answer is interesting because it's not purely mine, but instead
summarizes a poll of ~5 strong engineers at my previous company. Two years
later, I still think most of these bullet points hold, though I could also add
a few more advantages and a few disadvantages of using Clojure.

------
virtualwhys
Could substitute Clojure for Scala and the arguments made in the post would be
at least equally valid.

2014 is going to be a big year for the JVM as the Java 8 gorilla cometh. Will
be interesting to see what impact that event has on Scala/Clojure/Ceylon, etc.
alternate JVM language adoption.

~~~
bad_user
For languages that were designed to be "better than Java", then Java 8
represents a threat, however Clojure and Scala have very active and thriving
communities and contain concepts and ideas that go beyond "Java with
Closures".

I use Scala in production, have done so for the last 2 years, have been
learning a lot about FP and loved every minute of it. It's rather interesting,
because before Scala I basically wanted C# on top of the JVM. And now C# is
looking bland, bureaucratic, unproductive and I don't want it anymore.

Of course, many people hoped that some language will end up replacing Java as
THE language for the JVM. That never had any chance of happening, even if
closures would've never make it in Java. The people that wanted more capable
languages already moved on and the shops and software developers that continue
using Java will not change languages, because if Java worked well for them, it
will continue to work well in the future and everybody had plenty of
opportunity for change already. Java will still be the main language used in
the enterprise, simply because enterprise software development tends to favor
cheaper, easier to replace developers. Of course, this is one reason for why
startups tackling the enterprise space are thriving, but that's another
discussion.

Back to the point - we tend to think of languages and their evolution as some
kind of football tournament. For me it's rather uninteresting what language
will "win". I don't really care. All I care about is for a language to have a
sustainable and active community that churns out useful libraries. And some
people fear that they won't find jobs with language X. Personally I found the
contrary to be true - finding well paying jobs for working on interesting
projects in languages that are not Java, C#, C++ or PHP is much, much easier.
Things are easier also from the employer side, because you've got less noise
to deal with and usage of a certain language becomes one of the main
attractions for that job. In my experience, it's a win-win combination, which
is why I fear the thought of my favorite languages becoming too mainstream.
But then again, I don't really care about languages that much. All I care
about is for me to not suffer while trying to express what I want in code,
which is why I stay away from Java.

Anyway, I'm on my Christmas Holiday, so back to reading "Functional
Programming in Scala". It's a pretty cool book btw.

------
elwell
"going on other" => "going on in other" (actually that sentence doesn't make
sense anyways; somewhere around "were" it's gets confusing)

"perseption" => "perception"

"Fewer lines of code is a great thing" => [the opposite argument could easily
be made as well; more lines of code (within reason) = less obfuscation]

~~~
m0skit0
Fewer lines of code doesn't necessarily mean obfuscation, this is a language
feature. If Clojure is obsfuscated, then what is Perl, encrypted? On the other
hand, fewer lines of code definitely mean less bug probability.

~~~
elwell
I disagree that "fewer lines of code definitely mean less bug probability";
particularly with the word "definitely". Consider a section of six lines of
code that checks several conditions for the validation of a string. Now
consider a complicated regular expression that is on one line of code. I would
contend the likelihood of a bug to be much greater in the latter. Yes, this
does intersect with the concern of obfuscation, but I'm addressing the concern
of the number of lines of code. The complicated regular expression can make
certain edge cases nearly invisible, whereas the six-line conditional series
_lays out the problem more clearly_.

------
ChristianMarks
The Java Button Demo translated (or transliterated) into Clojure. If this
doesn't lead to instant employment, I'll switch to OCaml.

    
    
      (ns buttondemo.core
        (:gen-class)
        (:import [javax.swing AbstractButton JButton JPanel JFrame ImageIcon]
                [java.awt.event ActionEvent KeyEvent ActionListener])
        (:use [clojure.contrib.swing-utils]))
    
      (defn create-image-icon [path]
        (if-let [img-url (clojure.java.io/resource path)]
          (ImageIcon. img-url)
          (.println System/err (str "File not found:" path))))
    
      (defn enable-buttons [button-flags]
            (doseq [[button flag] button-flags] (.setEnabled button flag))) 
    
      (defn initialize-buttons [b1 b2 b3]
        (doto b1
              (add-action-listener 
              (fn [_] (enable-buttons [[b1 false][b2 false][b3 true]])))
          (.setVerticalTextPosition AbstractButton/CENTER)
          (.setHorizontalTextPosition  AbstractButton/LEADING)
          (.setToolTipText "I can disable the middle button.")
          (.setMnemonic  KeyEvent/VK_D))
       (doto b2
          (add-action-listener (fn [_] (prn "I told you not to click me.")))
          (.setVerticalTextPosition AbstractButton/BOTTOM)
          (.setHorizontalTextPosition AbstractButton/CENTER)
          (.setToolTipText "Don't click me.")
          (.setMnemonic KeyEvent/VK_M))
       (doto b3
          (add-action-listener 
             (fn [_] (enable-buttons [[b1 true][b2 true][b3 false]])))
          (.setMnemonic KeyEvent/VK_E)
          (.setToolTipText "I can enable the middle button.")
          (.setEnabled false))

)

    
    
      (defn -main [] 
        (let [[b1 b2 b3 :as buttons] (for [[title file] 
            ;         [["<html><center><b><u>D</u>isable</b><br><font color=#ffffdd>middle button</font>" "right.gif"]
                                         [["Disable middle button" "right.gif"]
                                         ["Middle button" "middle.gif"]
                                         ["Enable middle button" "left.gif"]]]
                                        (JButton. title (create-image-icon file)))
                panel (doto (JPanel.) (.setOpaque true))]
    
             (doseq [b buttons] (doto panel (.add b)))
    
         (initialize-buttons b1 b2 b3)
    
             (do-swing-and-wait
            (doto (JFrame. "Button Demo") 
              (.setDefaultCloseOperation  JFrame/EXIT_ON_CLOSE)        
              (.setContentPane panel)
              (.pack)
              (.setVisible true))))
    )

------
JackMorgan
I wish this didn't use the 590 core functions vs 30 Java keywords argument.
Clojure only has a handful of "special forms", whereas Java has dozens. A
better count would be all the methods in String, Int, List, Array, etc.

~~~
vorg
> With a total of around 590 unique functions7 in the Clojure core library
> alone that can be quite daunting when compared to C or Java which only range
> from around 30 to 50 keywords.

I count 19 special forms, 71 macros [1], 444 functions, and 29 variables in
clojure.core. I don't think we should count functions or variables because
these are like library functions and members (methods and fields) in other
languages. But both special forms _and_ macros are special in that they can't
be passed around in the executing code. There's 90 of those, which is
comparable to Java's 50-something keywords, or C#'s 70-something.

[1] excluding the 4 special forms `let`, `fn`, `letfn`, and `loop` which are
also macros

~~~
JackMorgan
The other thing that bugs me about a count like this as a metric, is it
doesn't speak at all to the complexity of the keywords. For example, think of
how complex the extends keyword is in Java/C#. Just that one keyword
represents usually one of the hardest things to learn about Java. Or the
defmacro special form in Clojure. Macros are a huge area of confusion when
learning a language. The count metric makes very little sense in explaining
the difficultly to learn a language.

~~~
vorg
Agreed, counting keywords in Java or macros in Clojure core isn't comparable.
For example, keywords such as `:when`, `:while`, and `:let` inside a Clojure
`for` macro support the macro name, perhaps in the same way `extends` supports
the `class` or `interface` keywords in Java. It would even be possible to have
only one publicly visible macro in Clojure with keywords in 2nd position to
chose the behavior, e.g. `(macro :defn myfn [a] (print a))`.

------
creese
Can your validation example handle checking at the map level (i.e. the case
where a required field is missing)? It seems like this is something you would
want to do.

~~~
m0skit0
You mean (contains? pred-val-map k)?

------
robin2
[Lightweight comment] The main thing that puts me off from learning Clojure is
the name. I mean, why not go the whole hog and call it funargs4j?

------
bonemachine
Oh, cmon.

Comparing any functional language to Java is just silly. As illustrated by the
Fibanocci example.

------
dkhenry
So if thats the best list I am happy I went with Scala. Especially the
Leiningen example. Is that seriously what needs to be written for a project to
build ? Its as bad as maven.

~~~
kodablah
To me it doesn't look that different than some project/Build.scala files I
have had to write.

~~~
dkhenry
You can build a scala project with a zero line build.sbt file.

~~~
adambard
Leiningen just insists you give your project a name. But, in the common case,
you used `lein new` to create your project folder, and a basic config is
provided by that.

------
michaelochurch
_Functional languages, as personal experience above leads me to believe, are
inherently more difficult to comprehend_

I don't agree with this. They seem "weirder" and harder, but they're not
intrinsically difficult. They're just less familiar.

Also, there are a huge number of people out there who think they "know Java"
but really don't. If you don't know what volatile and synchronized are and how
they work, for one example, you don't really know Java. I would say that,
unless everything in _Java Concurrency in Practice_ is familiar to you, you
don't really know Java.

Java and C++ are actually complex, difficult languages. The difference is
that, with "design patterns" and explicit managerial attention to differences
in ability (i.e. don't give mediocre programmers hard problems) it's more
possible to half-ass that knowledge.

~~~
agumonkey
The weirdness is such that I understand, actually I felt it was, more
difficult to comprehend. It's a complete point of view reversal. It ends up a
simpler model with lots of quality, but sometimes something different and too
simple is the hardest to understand.

