The biggest conceptual shift is to thinking functionally rather than imperatively, so it's going to be similar in both languages. The difference is that Haskell is more thorough, but the fundamental ideas are very similar.
Haskell, of course, has many of its own advantages which are mostly detailed elsewhere. I'm merely going to give you my highest-level take-away from trying Clojure: Haskell has much better facilities for abstraction. Haskell allows you to use types and data representation specific to your donation while still allowing you to take advantage of some very generic libraries. And the custom types are not actually complex, unlike what Clojure leads you to believe with its preference to using the basic built-in types: you construct your types from basically three fundamental operations: combining multiple values into one (like a tuple or struct), giving a choice of values (like a variant or disjoint/tagged union) or creating functions. That's all there is to them!
Basically, don't be afraid of Haskell, whatever the common wisdom is. As usual with these sorts of things, it's much more common than wise.
I've been using Clojure for about 5 years now. I've actively worked for the past two years on core.logic which has quite a few fancy abstractions (custom types, protocols, macros) that all interact quite nicely together. Now, I'm not a Haskell expert, but I do feel that some of the things I've built would be could be challenging in the Haskell context. I might very well be wrong about that.
That said, I'm actively learning Haskell as there are some aspects of Haskell I find quite attractive and in particular a few papers that are relevant to my Clojure work that require an understanding of Haskell. My sense is that even should I eventually become proficient at Haskell, my appreciation for Clojure's approach to software engineering would be little diminished and likely vice versa.
Of course, this is nothing at all like macros, but in practice we can achieve many of the same goals while maintaining type safety. So, win win win (the third win is for monads).
[1] http://stackoverflow.com/a/10857227/1579612 [2] http://www.haskellforall.com/2012/06/you-could-have-invented...
EDIT: As dons points out, I was imprecise in my wording. I don't mean to say that TH leads to Haskell programs which are not type safe. The compiler will, of course, type check generated code. In general, given that dons has been programming Haskell for 14 years compared to myself who has been doing it for 1 year, prefer what he has to say on this subject.
For logic programming: you might find Control.Unification [1] interesting -- and of course if you don't need unification then you can go pretty far with the plain old List monad.
Protocols/multimethods: Haskell typeclasses are really really powerful. Probably my favourite of all the approaches to polymorphism I've seen anywhere, although YMMV (they do lean heavily on the type system.)
Macros: there is Template Haskell [2], which is pretty interesting although I can't claim to've used it myself. It doesn't quite share the simplicity of macros in a homoiconic dynamic language, but at the same time in Haskell it feels like you don't need to lean on compile-time metaprogramming as much as you do in a Lisp to achieve power. (Can't quite put my finger on why).
[1] http://hackage.haskell.org/packages/archive/unification-fd/0... [2] http://www.haskell.org/haskellwiki/Template_Haskell
If there are some people out there who are well versed in both Haskell + Clojure, I'd love to hear some insight into where Clojure shines, and where you find yourself saying "Clojure is better at this!" in some distinct and meaningful way.
Also I think it really is easier to get started with Clojure than with Haskell, even for the (very well thought out!) concurrency primitives, though obviously that doesn't matter if you're already up and running with Haskell.
I use Clojure exclusively at my job, but for some things I really miss something like Haskell's type system, even though I freely admit I don't really understand the type system at its higher levels (specifically related to GADTs, existential types, type familes, etc.). Applicative functors would make some things so much nicer.
and you don't have to understand dependent typing to do it, either. I know there are heterogeneous list implementations for Haskell, but I can never understand how they work.With Clojure I have access to Swing (yeah I know...Swing isn't everyone's favorite) without installing any additional libraries. Then there is seesaw which is a very nice layer on top of Swing. To install seesaw I simply edit a text file in my Clojure project and the project management/automation system installs it for me. Very nice.
Discussions like this one convince me that we have advanced our programming techniques over the last decade or so. After all, we could be arguing about semicolons, the GOTO statement, or other similarly important issues.
It's a nice feeling.
In the abstract, possibly, but not in practice. You can't ignore the effect the general bent of the community has on the language and the code that is idiomatic in the language. People tend to describe Haskell code in mathematical terms, and libraries use operator overloading and the like in mathematical analogies.
Many of the people in the community do not know much of the math beyond the terminology they learned in Haskell. That's certainly what I gathered talking to people at a local Haskell meetup and it matches my impression of many of the people online (e.g. in the mailing list or StackOverflow.
https://github.com/Frege/frege
"Frege is a non-strict, pure functional programming language in the spirit of Haskell ... Frege programs are compiled to Java and run in a JVM. Existing Java Classes and Methods can be used seamlessly from Frege."
Large projects, I would go with Scala/Haskell and for front-end systems, I would use clojure.
Why do it this way? With clojure, you can easily modify data or small pieces of logic. Simply edit the script without the recompile. With the scala/haskell api or library, you probably need something that changes less frequently. That backend system may act as a core piece of your library. ...
And if you don't like that. You can do Python and Java/C# which can give you the same effect.
This is where Clojure has a slight advantage because you can tap into the Java ecosystem for stuff that isn't currently in the Clojure world.
Database libraries are a good example of this, database support in Haskell is still pretty flaky and cumbersome to setup in comparison to JDBC.
Haskell does have a bunch of advantages though. A pretty petty one is syntax: Haskell's is simpler, prettier, more consistent and yet more flexible. They're very similar, of course, but I think Haskell gets all the little details right where OCaml often doesn't.
The single biggest advantage Haskell has--more than enough to offset the module system, I think--is typeclasses. Typeclasses subsume many of the uses of modules, but can be entirely inferred. This moves many libraries from being too awkward, inconvenient and ugly to use to being a breeze. A great example is QuickCheck: it's much more pleasant to write property-based tests in Haskell because the type system can infer how to generate inputs from the types. Being able to dispatch based on return type is also very useful for basic abstractions like monads. Beyond this, you can also do neat things like recursive typeclass instances and multi-parameter typeclasses.
Honestly, if I was forced to pick a single Haskell feature as the most important, I would probably choose typeclasses. They're extremely simple and a foundation for so much of Haskell's libraries and features. Most importantly, typeclasses are probably the most obvious way the type system goes from just preventing bugs to actually helping you write code and making the language more expressive, in a way that a dynamically typed language fundamentally cannot replicate.
Laziness in Haskell is not really a big deal. It can make much of your code simpler, but it also makes dealing with some performance issues a bit trickier. It also tends to make all your code more modular; take a look at "Why Functional Programming Matters"[1]. I am personally a fan of having laziness by default, but I think it's ultimately a matter of philosophy.
And philosophy, coincidentally, is another reason to learn Haskell: it takes the underlying ideas of functional programming further than OCaml. In Haskell, everything is functional and even the non-functional bits are defined in terms of functional programming. Many "functional" languages are actually imperative languages which support some functional programming features. OCaml is one of the few that goes beyond this, but there is really a qualitative difference when you go all the way.
Once you know that everything is functional by default, you can move code around with impunity. You on longer have to worry about the order code gets evaluated in or even if it gets evaluated at all. You also worry far less about proper tail calls, which mostly compensates for having to deal with some laziness issues.
Haskell also embraces the philosophy in another way: you tend to operate on functions like data even more than in OCaml. The immediately obvious example is that Haskell has a function composition operator in the Prelude. There is no reason for OCaml to not have this, but--as far as I know--it doesn't. It's an illustration of the philosophical differences between the two languages. On the same note, Haskell also tends to use a whole bunch of other higher-order abstractions like functors and applicatives.
So I think the most compelling difference is ultimately fairly abstract: Haskell just has a different philosophy than OCaml. This ends up reflected in the libraries, language design and common idioms and thus in your code. I think that by itself is a very good reason to learn Haskell even if you know OCaml; and since you do, picking Haskell up will be relatively easy!
Also I've never seen Haskell's FFI work - it's just too much of a pain. Clojure's Java integration works right out of the box.
For what it's worth, I've found Haskell's FFI very pleasant for interfacing with C (and the reverse looks just the same, but I haven't tried). You then interface with any othet language through C, since most can FFI through C anyway. I think it's a very reasonable solution!
I guess this just shows that Math PhDs don't know how to use the fine profiler: http://stackoverflow.com/questions/15046547/stack-overflow-i...
Which would have saved about 5hrs 50mins...
Then you go on the describe what you find good about haskell? That sounded weird.
Custom data types are not always complex, but efficient and useful data types often are. Clojure's data structures have very good performance for immutable data structures. Clojure's maps, for instance, have what effectively amounts to a O(1) lookup, while Haskell's Data.Map is a size balanced binary tree with only O(log n) performance.
So O(log n) then. We obey gravity around these parts.
I presume you are referring to HAMT-like structures ,such as found in http://hackage.haskell.org/packages/archive/unordered-contai... which are by no means unique to Clojure.
Besides simply having the data type, you still need a good allocator and GC optimized for immutable data, which is where GHC stands alone - http://benchmarksgame.alioth.debian.org/u32q/benchmark.php?t...
Really? Because SPJ, for one seems to agree with it.
It is, of course, difficult to argue with zealots, but I will try nevertheless.)
The cost of what is called "advanced type system" is inability to put an elements of different types in the same list or tuple or whatever. It is not just a feature, it is a limitation. In some cases, when you, for example, dealing only with numbers, say, positive integers, it is OK, but what then the real advantage of such type checking?
On the other case, the concept of a pointer which all those "packers" trying to throw away is very mind-natural. When we have a box we could put anything in it, as long as it fits. Imagine what a disaster it would be when you moving from one flat to another but must pack stuff only into special kind of boxes. This one is only for such kind of shoes, this is only for spoons, that for forks. So, with a pointer we could "pick up" everything, and then decide what it is and where it goes.
Another mind friendly concept is using symbols and synonyms to refer to thing - s symbolic pointers. It is how our minds work. Those who are able of thinking in more than one language know that we could refer to it using different words, but "inner representation" is one and the same.
These two simple ideas - using pointers (references) and have data ("representation") to define itself (type-tagging is another great idea - it is labeling) gives you a very natural way of programming. It is a mix of so-called "data-directed" and "declarative" and, as long as you describe a transformation rules instead of imperative step-by-step processes, "functional" styles.
Of course, the code will look in a certain way - there will be lots of case-analysis, like unpacking things form a big box - oh, this is a book - it goes to a shelf, it is a computer speakers, it goes on the table, etc. But that's OK, it is natural.
The claims that "packing" is the best strategy is, of course, nonsense. Trying to mimic natural processes in our mind (as lousy as we could do it) is, in my opinion, has some sense.
There are some good ideas behind each language and not so good. Symbolic computation, pattern matching, data-description (what s-expression, or yaml is) are good ones. Static typing, describing "properties" instead of "behavior" - not so.)
Also it is good to remember that we're programming computers, not VMs. There is something called "machine representation" which is, well, just bits. It doesn't mean to swing into another extreme and program in assembly, but it is advisable to stay close to hardware, especially when it is not that difficult.
Everything is built from pointers, you like it or not.) The idea to throw them away is insane, the idea (a discipline) of not doing math on them is much better. The idea of avoiding over-writing is a great one, it is good even for paper and pencil - everything become a mess very quickly, but avoiding all mutation is, of course, madness.
So, finding the balance is the difficult task, and it is certainly not Haskell. Classic Lisps came close, but it requires some skill to appreciate the beauty.) So, the most popular languages are the ugliest ones.
I can't say I managed to completely understand the argument you're making here, but doing mostly Java/Python for work, I don't remember the last time I had to write a heterogeneous list. At worst, you can always go for existential types.
1) Immutable data structures are always going to be slower than their mutable cousins.
2) "Clojure code is beautiful" should be changed to "Your OWN Clojure code is beautiful". When I finished writing a compact piece of logic or data transformation, I was often struck with the beauty of it. When I tried to read someone ELSE's Clojure code, however, I couldn't even begin to make sense of it.
I am ever open to being proved wrong, however. Any Clojure programmers reading this, please reply with some code that is readable, elegant, and performant, to provide a counterpoint to my pessimism.
Not always. It depends on usage. Mutable data structures can actually entail more work if the data needs to be accessed from more than one place. Immutable data structures can be shared and reused much more freely. (For example, adding an item to an array you got from somebody else means either the caller or the callee needs to have copied the whole array, while adding an item to an immutable list you got from somebody else means creating a single cons cell.)
At any rate, even if a destructive solution would be faster, the functional solution will probably still be faster in Clojure than the destructive solution would be in Ruby. And if not, you can still do something destructive — it's just not the default.
> "Clojure code is beautiful" should be changed to "Your OWN Clojure code is beautiful". When I finished writing a compact piece of logic or data transformation, I was often struck with the beauty of it. When I tried to read someone ELSE's Clojure code, however, I couldn't even begin to make sense of it.
I believe this is largely a matter of experience (not completely — some code just is hard to read!). Most people get that feeling when they're working with a relatively unfamiliar language. I find that the more familiar I become with Clojure, the better all other Clojure programmers seem to become.
That could be. However, I believe it's more to do with the fact that idiomatic Clojure encourages continual definition of nested layers of abstraction. Which makes the code beautiful from a certain viewpoint. However, it's also very similar to essentially writing a new language and adding features to it. If you buy this comparison, then reading your own Clojure code is like reading code written in a language you wrote, which is tailored to your own ideas about aesthetics and interfaces.
Which is great. However, that would then mean that in order to read anyone else's Clojure code, you would have to learn a new programming language every single time. I would buy that this gets easier the more you do it, because my second programming language was definitely easier to learn than my first.
That said, there is definitely some nasty Clojure code out there, but I'm not sure that's avoidable in any language. Fortunately, the conventional wisdom to only use macros when necessary has started to catch on and that's made the situation a good deal better.
I'm not really arguing that Clojure code is "truly" difficult to understand, if that is taken to mean reasoning about its performance and effects. Rather, I'm talking about the fact that idiomatic Clojure code encourages writing functions upon functions upon functions, which continually builds up layers of abstraction that inherently make code more and more difficult to read. Example:
console.log("Hiya.");
console.log("How's it ");
console.log("going?");
vs.
printFirstString();
printSecondString();
printThirdString();
function printFirstString() { ...etc }
I think you are totally right with regard to reading other people's clojure. Sometimes it's easy and pleasant, sometimes inscrutable.
I think the issue at hand is that it is so easy to go the DSL route in clojure. I call that an issue because when you invent a DSL to solve your problem, you've essentially created a new language that only you understand.
So now, if I'm reading your code, I have to understand raw clojure, and then I have to try to figure out your DSL.
Here's a microbenchmark I just threw together in a REPL, since you ask: The operation is to create a map data structure, then, ten million times, add/assoc a key value. The key is the .toString() of a random integer between 1 and 100,000. The value is the integer.
Therefore, the resulting map will end up with a size of 100k elements, and be modified 10m times.
Except for the map implementation used, the code is identical.
I ran each test six times, discard the first three (to allow the JVM to warm up) and took the average result time of the other three.
The results on my 2010 MBP:
java.util.TreeMap: 8573ms
java.util.HashMap: 3243ms
Clojure immutable hashmap: 7909ms
Clojure immutable treemap: 21248ms
Clojure hashmap (using transients): 5113ms
This is true, and I've read some of the papers describing said structures and was blown away by the cleverness. However (and I don't have a source here, so please forgive me if I'm just totally wrong) I have watched many of Rich Hickey's hour+ long talks, and in one of them, I distinctly remember him saying that his vectors were "Within an order of magnitude of mutable vectors performance-wise, which is good enough for me".
I was... put off by that.
EDIT: Now that I think about it, it might have been Maps that he was talking about. I are not good at remember.
True in general, but only if you just care about single core performance. A data structure that allows your algorithm to scale gracefully to more cores is actually more performant than a data structure that's faster for a single thread, but is extremely hard to scale in concurrent settings. Clojure sacrifices single-thread performance for multithreaded scaling, and it's the right tradeoff given current hardware trends (for example, consider the design of Clojure's reducers, and how it focuses on multi-core scaling).
My main concern with immutable data structures (and most data structures designed to work in concurrent settings, actually), is their heavy reliance on garbage collection, and on old-gen garbage collection in particular. Old-gen GC still has some ways to go, at least in HotSpot.
This is in comparison to reading an OO library in a language I'm much more familiar with but where inheritance / mixins mean you have to dig through many files (often not obvious which ones) to understand a piece of code.
They allow mutation as long as it's localized.
This would be ok, if immutable data structures weren't also much harder to reason about, implement, and actually use in your algorithms. Nothing is stopping you from doing functional programming and using immutable data structures in an imperative language (the reverse is very much not true), but why would you bother if it's easier to think about (and prove properties of, if you're into that thing) mutable data structures?
People recommend Okasaki's Purely Functional Data Structures all the time, but the main result of that dissertation aren't the clever immutable data structures, it's the fact that Okasaki was the first person to come up with a somewhat workable way to do asymptotic runtime analysis of immutable data structures. IMO it's not pretty.
Anyone who has spend a few days with Clojure realize how much more easier it is to reason about them and to work with them.
Immutable data structures combined the software transactional memory that Clojure provides are a godsend.
In a lot of case they're also much faster then the good old copy-on-write and because they're immutable you have lockless concurrency. This is huge.
But it gets better: if you really find a performance bottleneck due to the use of immutability, you can fallback to mutability / place-oriented-programming.
This is also very telling - lets you deploy your Clojure Web app to a JBoss server and take advantage of JBoss’s scalability without any XML configuration. You get a mature enterprise-ready Java server without the pain of Java or of configuration.
I wonder how many orders of magnitude difference in "scalability" we would see with a simple nginx -> fastcgi -> sbcl setup.)
Memory usage under long periods of time with pending storage/back-end calls is also interesting topic - how JVM blows up just after few hours in "production".)
More importantly, it doesn't have a focus on immutability and functional programming by default.
I'm not even sure what you mean about the JVM blowing up after a few hours... Tuned correctly it'll stay up indefinitely.
In what way? The Common Lisp standard hasn't changed since 1994.
> essential features like multithreading are not standardized
No one has made up their minds what the best atomic test-and-set operations are. A lot of platforms can't even agree on semaphores vs. condition variables. Which concurrency primitives do you think should be standardized, and which should be left to libraries? To me that seems like a trick question, because there's no good answer.
For example, I think software transactional memory is a dead-end, and shouldn't be part of a language standard, but many people involved in Clojure obviously disagree.
> More importantly, it doesn't have a focus on immutability and functional programming by default.
You can always do FP in Common Lisp, but you can't do gotos in Clojure.
CL, and SBCL, are great, but SBCL uses a conservative garbage collector (or at least it did the last time I used it) so I'd say the chances of having memory problems with Clojure are less than with SBCL. In fact I remember having some memory issues with SBCL though I no longer remember the details.
Being able to disassemble functions is a great but honestly I don't miss that option in Clojure.
Clojure's a great language that's really worth trying out. I'm not saying it's perfect, there are still warts, but it's immensely satisfying too.
It is easier to give a jar to the devops team, than trying to convince them to add support for yet another language the crazy developers are now trying to use.
besides which eclipse is a finicky monstrosity like visual studio
You know yourself far better than I know you, and so why would I presume to tell you how to live your life?
Functional programming is sometimes great. Most forms of programming are sometimes great. But I don't think there is one form that is great all the time. Maybe there is, and maybe if I come across it I'll be smart enough to recognize it... but in the mean time, I'll just try to use what makes sense to me.
And sometimes, functional programming just doesn't make sense to me. I still can't quite get my head around monads. They have just one or two too many levels of abstraction for me to hold in my head. I think I'm almost there, and was trying very hard to grasp them, but then in one of the videos I was watching, the guy said this: "Monads are a solution to a problem you will never have." He said it in jest, partly because the language at hand was Javascript, but it really stuck out to me.
Clojure has what I would call "sensible" state containment via STM. And sometimes just plain storing some state is the easiest and most straight forward way to go.
I love working in Clojure because it makes it so easy to break down problems into bite sized functions. That, and the concision of the syntax suits me. I'm trying to accomplish the same thing in Java by having some classes that I treat as a namespace and load them up with static functions in that namespace. I'm sure a lot of people would spontaneously barf on their screen if they saw my code though.
Basically, the reader can decide for themselves. Also, each reader reads more then one blog post. So having a bunch of extreme opinions to compare (e.g. a strong case for a bunch of different languages) is more useful than a whole bunch of hedged blog posts that all repeat the same refrain: "well, all languages are basically equal and you should use what seems best".
In fact, blog posts like that are a big waste of time. (I'm looking at you, prog21.) I would much rather hear a bunch of different, reasoned opinions--especially if they contradict each other--than hearing the same boring, condescending tripe about choosing "the right tool for the right job" over and over.
Also, I think the idea that all--or even most--programming languages are somehow equal is patently absurd. Similarly, I think the oft-reused tool analogy is deeply flawed. But that's neither here not there and enough material for a blog post of its own.
Of course, that's something of a false dichotomy, although it does come up in practice. But I think posts advocating a technology are also good by themselves.
The choice of technology may be subtle, but this post only needs to present one option, which it does admirably.
> I will tell people that I like something, but I never tell them
> that they must use it.
I think it's just a "dude, you've got to check this out" sorta thing. Not really a command but that special itch to just share your opinion with someone.I gravitate towards the tools/technologies/paradigms that compel this sort of enthusiasm every time.
* Martin Odersky's (and the general community's) enthusiasm led me to pursue Scala and convinced me to take a serious stab at functional programming.
* Rich Hickey (etc.) to Clojure.
* Sandi Metz (etc.) to object-oriented design.
* DHH (etc.) to Ruby and Rails.
Vim, Coffeescript, Alfred, Postgres, tmux, Crystal Reports, Dropbox, most my entire toolchain, where I went out to eat last night -- all cajoled by the infectious enthusiasm of others inspirited by those things.
This is exactly the problem I had. My canonical "getting to know your new language" project is always writing a simple chess engine. After writing a few of the high-level constructs, my next step was to try to browse some other .clj libraries, because I was pretty certain that a lot of the tedious tasks involved in writing a chess engine had already been solved.
After reading their code, I very quickly gave up.
There isn't really a single framework, rather you can pick and choose your components depending on your needs or preferences.
In Sinatra or Flask, you get a server (interface), a routing syntax, and built-in templating.
In Clojure, you have Compojure, which handles routing, Ring, a server abstraction for requests, and responses, and the templating library of your choice. (I've used Hiccup and Enlive, as well as Mustache and Markdown). You're responsible for gluing them together, which is really not too hard given the power of the language to create abstractions on the fly. This results in slightly more code, but also makes it much easier to replace or augment any one component.
From there, and for other errors, generally I use print debugging. Often times you can also just test a function in isolation on the REPL. This and the fact that you can hot-load code into a running process make print debugging tolerable.
There are fancier debugging tools in development for clojure, though I have no experience with them. Essentially they let you attach a REPL at arbitrary failure points. This would make it quite easy to identify the source of the problem.
Knowledge of the JVM does come up, but you won't be digging through compiled bytecode or the guts of java libraries (unless you use a lot of java library interop).
Debugging tends to be more REPL based than debugger based. It is possible to debug from Eclipse using the build in debugger, but it's not something i have done as it is not really necessary.
Coming from Scala/Play my initial resistance to jumping the fence are: 1) lack of compile time type safety 2) odd, for me, language syntax 3) no ScalaQuery/Slick functional SQL wrapper equivalent
How is Scala-Clojure interop? Would be interesting to jar up existing Slick-based model layer and invoke within Clojure stack ;-)
Not having yet taken the plunge, based on the LightTable demo Clojure development seems pretty rapid fire (read: no waiting for compiler to catch up).
ClojureQL, however, looks intriguing, seems more functional than the alternatives listed here.
Would love a more rapid fire development experience than what Scala/Play offers, but for now there's a price to pay for type safety.
Clojure seems a great call for the dynamic side of the fence, and being on the JVM with its massive ecosystem is a major plus.
"And—if you like avoiding unnecessary frustration and boilerplate—it will make you happy."
Didn't get this feeling. I like avoiding unnecessary frustration and boilerplate! A great way to avoid boilerplate is to hide it behind macros, however that's not necessarily a great way to avoid frustration.
Know what's really awesome? When a macro injects a recur point, and suddenly you're not recuring to where you think you are, you're recuring to a point within the macro somewhere. The only way to figure this out is to go dig through the source of the macro.
Sorry Clojure fans, what can I say? This did not make me happy. I am told that if Clojure did not make me happy, that's my fault, because I didn't study Clojure hard enough or something to get to the point where I should feel the Zen of Lisp flowing through my brain. Clearly this must be the blub paradox at work.
Maybe it's my fault, or maybe Clojure isn't the greatest language in the world for everyone.
As for macros, they should be used with care for many reasons, this being a good example. Similarly for ruby, monkey patching should be use with great care as it can introduce more problems than a surprise recur point.
A macro injecting a recur point sounds just a little bit insane. I can't think of a reason why you'd ever do that.
Given my experience on international enterprise projects I think:
- static languages win over dynamic ones, because most teams only write tests if obligied to do so, and even then most tests aren't proper. At least it makes sure the code is in a compiled state.
- most developers on the teams are google-copy-paste monkeys that only have basic understanding of Java/C#/VB so they need similar enough syntax to do the transition to new languages.
Still fairly early days on that though (missing protocols and rest parameters are the big issues I think)
Regardless, it doesn't seem to affect desktop development, so Clojure on!
"Leiningen and Cake, joined forces to become an all-powerful build tool. Then Leiningen reached version 2. (And let me tell you, Leiningen 2 alone makes Clojure worth using.)"
Other build tools, and package managers, such as "bundler" in the Ruby world, seem pretty weak compared to Leiningen. This is a very powerful tool.
The tooling and the eco-system are reaching a very powerful level. For now, I use Emacs as my editor, but I am waiting for LightTable ( http://www.chris-granger.com/2012/11/05/meet-the-new-light-t... ) to get just a little further, and then I intend to switch to it.
This whole article is good, but this is the part that gets to the heart of the matter:
"Rubyists know that their language effectively got rid of for loops. In the same way, Clojure gets rid of imperative iteration in favor of declaration. Your thoughts shift away from place-oriented constructs like memory and gravitate to data structures and functions like map, reduce and filter. Your “class hierarchy” turns out to be a type system that happens to also lock away well-meaning functions into dark dungeons (more on that in another article), and getting away from that is freeing."
That might be the best summary of the strengths of Clojure: it helps you think about data structures and transformation, rather than thinking about the ceremonial and imperative code that your language needs to hear.
My only grumble with Clojure is that nobody seems to document the types that their functions take and return. It's a PITA having to read through a whole chain of functions just to figure out the types which are passing through it.
I'm still in the process of learning from the Clojure gurus around here but I see that it has a lot to recommend it. I can already see increases in the clarity of my code when I write filters and functions for our data pipeline. The next step is to learn Cascalog.
We're fielding a sizable contingent to the Clojure West conference this weekend (which we're also sponsoring) so come say hi if you're in out in Portland!
What I do know, is that I was in love with Assembler since my first steps in programming and hacking. While everyone in my surroundings were using pascal and basic that days, inlining asm only for occasional IO work, I used to scaffold tremendous routines and structures in a matter of days, using base asm and macro. While my friends, looking at my sources, were only able to say "what the ...ck is this, that is insanly sick, how do you understand all this?", asm was so natural and fluent to me.
Then dark times of C and C++, Java, C# etc. followed (BTW, I hate purified OOP deep inside, it always seemed to me so unhuman), and several years ago my roads crossed with LUA, and I instantly loved it. Pity, I had no chances to use it much, but I remember that feeling, when code and data magically interlace and create beautiful structures.
Now I am looking at Clojure and recalling my Asm youth, and these awesome days with LUA. But this time it has all the power of interop with major libs and services. I am giving it a try.
Can someone point to an A/B comparison ... a simple Rails/Django app and the Clojure equivalent?
"Just show me the code."
Fast, RnRS/IEEE Scheme compliant, has a great runtime layer and FFI, can integrate with anything written in C.