Hacker News new | past | comments | ask | show | jobs | submit login
Why use Clojure? (paradiso.cc)
132 points by iamtechaddict on Dec 24, 2013 | hide | past | favorite | 104 comments



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.


I know your feeling, I've programming in Clojure for one year now (although I don't have time to program with it full time). I think your kind of problems are more related on "how" you use Clojure rather than Clojure itself. Errors are obscure only if you try to do too much things in one function. Try to keep functions as simple as possible and to do one task per function, no more. Then message errors are not that hard to figure out, although yes, I agree that for example in Java errors are easier to figure out (but definitely not fixing them...). And anyway using the REPL you can test one function at a time, given it's a pure function, which is also a new state of mind: eliminate all possible mutable state.

I've found that when using Clojure you have to think in a different way about the problems to be able to "see" how your problem can be resolved in Clojure in a more elegant and concise way. This is hardest task I've found when moving to Clojure from Java: change your mind. With the right mindset, everything (in my case at least) seems like pretty trivial in Clojure, and definitely much faster to code and test than Java.


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.


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.


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.


>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.


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.


To address one of your points, I've found it much easier to get a complex line of clojure code working since I started using the InstaREPL in LightTable.

It shows the REPL output of each line of code as you write it, which is spectacularly handy.


LightTable is nice, and I eagerly await some stability. But I somehow foobar my session and have to restart the repl all the time. Slow as hell.

Not to mention, LightTable started out as something special and morphed into something mundane. I have high hopes that it was just organiziation and the cool shit we saw at the begining will come back via plugins, but right now it's just not there compared to vim or emacs.


Care to explain about LightTable starting special and morphing into the mundane? I've checked out a few versions along the development cycle and I wouldn't say that's the case.

Also, it's not "foobar", but FUBAR: Fucked Up Beyond All Recognition/Reason/Repair.


Go look at early versions. The concept of files was secondary for example. Program flow meant something. Not it's just a text editor. I am hopeful big changes are coming though.


They are :)


You are generalizing your experience and treating it as though it were some universal truth. I am far more productive in clojure than in go.


your post is recursive.


No, it is a counter point. Demonstrating that all you can glean from someone's personal experience is their personal experience, not some universal truth about the languages.


That's a bit facile. The evidence for "universal truth" comprises many data points, of which DigitalJack's is one, and yours is one. It's not that the approach is invalid or the anecdote uninteresting, but that these are samples of size one (i.e. anecdotes) and hence insufficient for inference.


Yeah, that's what I was saying. He is taking his personal experience, and generalizing it as if it were a universal truth. That's why I said exactly that.


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...

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...

At this point RoomKey is a lot bigger than Hipmunk.


It's hard to write any kind of essays that try to show that X is better than Y in the realm of Programming Language + Platform (yes, Programming Languages these days don't buy much if the Platform is under-supported even though the majority won't admit it).

If you wrote too high-level without enough details, people would call you out for "supporting your argument without any merit".

If you wrote too technical/low-level, it looks like a script kiddie toy and not "for production ready system with complex requirements and multiple stakeholders with evolving needs".

I gave up convincing people a while ago and just focus on get things done. Java, as verbose as it is, still productive enough for me thanks to the ecosystem + tools + libraries + etc.


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.


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


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.


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.


Clojure, being a Lisp, uses the tradition of a REPL (Read-Eval-Print-Loop). The REPL handles all of the command line parsing and printing for you. All you do is load up your program and start calling functions with it. It makes for a great interactive development tool, as it can be used within most editors/IDEs which tend to have commands for automatically reloading all your code in the REPL.


Fair enough, but then the difference between the two languages is not linear across the development of the larger program. The largest difference in code size is displayed, but it focuses on boilerplate code being the inflating factor of Java.


Yeah, focusing on boilerplate is not all that interesting in the long term. For large applications (which both languages aspire to), it makes more sense to compare things such as static vs dynamic types, mutable vs immutable, etc.

Though I guess there is some merit in having less boilerplate, as fewer lines written mean fewer lines to modify during a refactor/debug session.


That would be a good excuse for the apples to oranges comparison if people always ran production server code via the REPL.


It's actually possible to connect to your production server through a REPL and hot-swap code.


It's possible to connect to a production java server and hot swap code via eclipse. What's your point? Probbably not a good idea to do this for any real production system.


One of the big features of erlang is intelligent hotswapping for building robust telecom systems that never go down, but can be bug fixed/upgraded on the fly. Just because something is not commonly done with current tools doesn't mean its a bad idea, just that it is a bad idea with current tools.

My understanding is that built in java hot swapping is very limited, and indeed would be a bad idea to try hotswapping in production.

If the clojure repl brings us closer to the erlang world isn't that a good thing?


The type of code swapping you are doing with the repl, eg coding on the fly in the prod systems, and the type you are doing with erlang are completely different.

Erlang does have a much better deployment story than jvms as far as code swapping.

But AFAIK Clojure is compiling to bytecode and is under the same constraints as the JVM that it is hosted in.


> But AFAIK Clojure is compiling to bytecode and is under the same constraints as the JVM that it is hosted in.

This is true for certain features (protocols, records, and gen-class, which are easy to avoid for everything but high-performance bottlenecks and legacy interop), but vanilla Clojure functions are built around vars, which are specifically designed to support reloading.

edit: it's still primitive compared to Erlang, but it's miles beyond Java.


True good point. I still maintain that it's not a great idea in production and it really doesn't scale. I did stuff like this in single host servers in rails as well. Turns out to not be so repeatable and not a great idea in prod. Also isn't great if you bring down one node of prod or if you have a load that takes more than one box worth of processing.


I agree, but I would qualify that claim: it's not a great idea in production because the tooling to support doing it well doesn't exist, not necessarily because of limitations in the language.


also. I have absolutely no idea how the first one even works.

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


It's sloppy copy/paste work from http://en.wikibooks.org/wiki/Clojure_Programming/Examples/La...

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.


It looks like an error. The author probably based his code on an example from Wikibooks [1]:

    (def fib-seq
         (lazy-cat [0 1] (map + (rest fib-seq) fib-seq)))
But, since he added an argument to the function, I don't think his code actually works, even if you ran :s/fib-seq/fibonacci

[1]: https://en.wikibooks.org/wiki/Clojure_Programming/Examples/L...


I don't know Clojure, but I assume it's supposed to be:

  (rest fibonacci) fibonacci)
i don't know actually...


Not to mention you could easily rewrite the Java version in one line with a conditional, if you wanted. Whitespace in your code isn't always a bad thing IMHO.


You focus on one example to say "not very convincing"? Please elaborate more on why Clojure features are "not very convincing", I would like to hear your opinion.


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?


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.


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.


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.


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


I don't know a Clojure. Why should knowing understanding one language imply that you automagically know another? If you know Spanish, Portuguese May look familiar but it won't be exactly the same. Does that mean you should understand Korean or Japanese?

From the little bits of dabbling with various lisps in have done a functional language is different enough from my bill paying regular languages (JS, php, Java) that without a focused study on a project that hits several layers of a typical stack, I fully expect the language to be foreign to me. Until I know the 350 core language operations by heart I'll not be able to play with them. If I cannot play I'll never be able explore the language and use and misuse it until I can make it do what I want it to do.

So the fact that it looks encrypted to you is a good thing. It's a code waiting for you to break it. It's a problem waiting. A small group of extremely intelligent people are responsible for the family of lisps. That tells me that if/when I do dedicate the time and effort to understanding the lisp tools it will be worth the effort.


The thing that helped me most when I started learning clojure is to mentally move the parenthesis over to the other side, so

    (println (max 34 64 15))
becomes

    println(max(34,64,15));
and vice-versa.

Another thing that helped is realizing that almost all things that require special syntax in other languages look like function calls in clojure. So, for example, to create a new function, you call the defn "function" and pass it parameters for the name of your new function, the expected arguments, and the body of the function.

The last thing is remembering that in clojure, the last statement in the body of the function is automatically the return value of the function, so I just imagined that the last statement had a "return" call in front of it.

With these 3 rules I could mentally translate 95% of clojure* to c-style code and back.

*The other 5% is mostly about macros, which are what give clojure (and other lisps) the power to add new features to the language via libraries, among other cool things. They they're powerful and used sparingly though, so you won't bump into them too much, and when you do, most will be documented as to how to use them properly.


> almost all things that require special syntax in other languages look like function calls in clojure

I would say that most syntax in other languages is there precisely so that not everything looks like a function call.


Good point. I suppose that the trade off is that you loose the "marker posts" from other languages that say to the programmer "Magic happens here, go read the docs" but you gain the power (together with macros) to add features to your language seamlessly.

In fact I think that only 13 "functions" are "magic" in clojure (as in written in java), and the whole rest of the language is written using those 13 functions[1]. That would be like, for example, adding golang's channels to ruby syntax by writing ruby code, without having to drop down to C, which i think is pretty cool.

I also found it very useful in real-life, mostly through having clojure libraries that can do things more seamlessly than similar libraries in other languages. For my last project, I needed to use maybe monad functionality quite often, and having it be as easy to use as the core language in my code was a huge win for my sanity.

[1]: I think some of the data structures are written in java as well, but only for performance reasons.


I find that those syntactic markers make it so much easier to parse the structure of code at a high level, and their lack (or the way they can be embedded inside other expressions) are what has always kept me away from a variety of languages, from Lisp and Forth all the way to CoffeeScript and Haskell.


If you already have a background in each of Ruby ,Python, Haskell and Haskell you probably can learn a good chunk of Clojure in a weekend, as it shares many features with these languages. The main difference, of course, is the prominence of lispy prefix function calls delimited by parens. Well, and macros, but Ruby does some of this.

Some links: http://blog.fogus.me/2010/06/09/clojure-rb/ http://stackoverflow.com/questions/4509782/simple-explanatio... http://jkkramer.com/sudoku.html


Unless you're a native Greek speaker. My point being that prefix notation is not something common in programming languages, but that doesn't mean it doesn't work or it's obscure: it's obscure to you because you're not used to read it, that's all. And yes, maybe the example is not best example.


What would objectively define "readability"? I hear this word thrown around a lot without much thought given to what it means. As far as I can tell whether a person considers a language "readable" is really only correlated with whether they were first taught a language with similar lexical syntax. People who were taught Scheme consider sexp based languages more readable, and people who were taught C/Java prefer semicolon delimited block-like languages.


When someone says "readability" I have come to realize they mean: "I can read now".


One of the reasons I think people may find clojure hard to read is that there isn't much vertical spacing. Do you find this translation of js to clojure any easier?

function doThis(arg1, arg2){

    var m = arg1 + 3;
    var n = modifyArg(arg2);

    if (m > 3){
        System.out.println("bigger!");
    }

    return m + n;
}

(defn do-this [arg1, arg2]

    (let 
    
        [m (+ arg1 3)
         n (modifyArg arg2)]
    
        (if (> m 3)
            (println "bigger!")
        )
        
        (+ m n)
    )
)

I'm not suggesting this is good clojure, but it's closer to the way imperative languages are written.

One thing which still causes me to expend a few extra brain cycles for me is the [] in the let clause. The fact that the locally scoped vars m and n are contained within a syntactic block, as it were, makes me feel that they're within an inner scope and not available to the code below. It's really trivial and absolutely a feel thing, but it does have small effect on the ease of readability.


This is why I like nimrod, which gives you the best both worlds

    proc doThis(arg1, arg2: int): int =
      let m = arg1 + 3
      let n = modifyArg(arg2)
      if m > 3:
        echo("bigger!")
      return m+n
With the added bonus that you get compile-time type checking (as well as a fair bit of type inference - notice I didn't have to specify any types other than the function signature), and the code itself compiles down to highly efficient C (https://gist.github.com/tylereaves/8116774 if you're really curious, do remember that code isn't intended to be human readable/modifiable).


Yeah, in thinking about my example a little more and generalizing, I think one of the problems that people have with reading clojure is that it doesn't have as robust a syntactic indication of scope that other languages have.


Don't you mean clojure has a MORE robust indication of scope than other languages? In clojure you can nest lets, and it is very obvious when the binding is out of scope, but in c-style languages, once bound, they stay bound till the end of the function.


Nope, Nimrod (at least) has full lexical scopes if you want

    proc foo(x: int): int = 
      let z = x * 2
      #z visible
      block:
        let y = z * 4 #z & y visible
      let foo = 3 #z and foo visible, y out of scope


I said "c-style", not ML style.


I don't find the example Clojure in the original article terribly readable, speaking as someone who writes a decent amount of Common Lisp.

My real entry into the Lisp world was via Perl and the higher order functions that I used there. That enabled me to grasp the overall semantic of Lisp; lots of time in the code did the rest.


In your case, I'd recommend you learn Scheme first. The Little Schemer and of course, the almighty SICP, will be of help.


Let me recommend DrRacket, it is an excellent IDE, and has great built-in documentation to explain what you can do. http://racket-lang.org/


I second this.

I really like Clojure, and it's what I started with in terms of Lisps. When I wanted to explore more "traditional" Lisp, I looked into Common Lisp, and it didn't thrill me. It felt old to the point of decrepit.

Racket feels very modern, and very polished. I'm trying to groom it as my go-to scripting language.


Take a gander at the javascript/clojurescript synonyms cheatsheet, it's a lightweight way of seeing the mental transformations you need to do to get from a curly brace language to a s-expression based language: http://kanaka.github.io/clojurescript/web/synonym.html


I'm not a Clojure programmer, but I have an interest in things that run on the JVM. I went through this semi-quick guide to get an overview of how the language and syntax works:

EDIT: actually this was the link I meant to post. It was on HN a couple weeks ago: https://docs.google.com/presentation/d/15-7qFy6URdE7Owi2Litk...

EDIT: Not this link, though it looks interesting: http://www.innoq.com/blog/st/presentations/2010/2010-05-20-C...


You don't need to "know Lisp" in the sense of being proficient, but you need to be familiar with s-expressions. Once you grok s-expressions, the rest is "just" grokking a bunch of functional idioms not specific to Clojure.

Actually if you're familiar with Haskell then Clojure idioms should be more familiar to you. Clojure's datatypes are (almost all) immutable, driving it towards a lot of functional idioms you see in such as Haskell or maybe Scala.


Immutability is not the whole story. There is also parametric polymorphism, algebraic data types and pattern matching (best case analysis tool ever), type classes for type constructors (not just types), etc.


Of course. That said, Clojure doesn't have those, given that it has a dynamic type system and destructuring instead of pattern matching (not as clean, IMHO), so a comparison to Haskell in this respect is less useful.


My point was that it is perfectly possible to be familiar with Haskell and find Clojure (and Lisps in general) puzzling.

On the other hand, I would be genuinely surprised if someone familiar with Haskell were unable to pick up ML, or vice versa.


If you want pattern matching, check out core.match


Where is the exhaustiveness checking?


C code can be unreadable and sometime pure poetry. Lisps are the same. One difference though, s-exps are the most editable thing in the universe, paredit-like interaction makes you forget the superficial lack of readability.


You're right, you might need to spend 15 minutes reading a basic tutorial or cheat sheet.


I wrote an answer to this question on Quora a while ago: https://www.quora.com/Clojure/Why-would-someone-learn-Clojur...

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.


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.


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.


I agree Java 8 will be big. I have started experimenting with Java 8 language features. I use Clojure a lot, and I occasionally use Scala. Java 8 features might get be using Java again for new projects.


I don't know about Scala, but you can check poster's link at the bottom on Scala vs Clojure.


"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]


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.


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.


"it's gets" => "it gets"


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))))
)


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.


> 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


Yeah, ok, I see what you are getting at with the macros not being the same as a function that can be passed. I used the wrong word when I said special forms, I was referring to "unusul syntax" stuff like #(), [], {}, anything that isn't just a list. You are right though, while I found the clojure special forms much more regular than Java's keywords and therefore much easier to learn, since they sometimes defer evaluation, they should probably be treated as a separate case.


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.


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))`.


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.


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


[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?


Oh, cmon.

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


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.


what needs to be written to create a project and build/run it is:

    lein new twitter
    lein run
that's it.

Most of the info in this article just reflects the rightful excitement form the author, but not in any way the best or the simplest way to do things. Just take it as "I love it, let me share" vs. "Clojure is better than..."


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


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


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.


You can also build a Java project without any kind of ant/maven/shell script at all. Apples vs. oranges.


Bad? It's orders of magnitude better than Maven. It's actually as lightweight as JSON.


A Scala guy who has to deal with SBT is complaining Leiningen? Seriously?


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.


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.


OMG such truthiness! Who are you? Can I make you a statue in my city? :D




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

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

Search: