Clojure: The JFDI language
docs.google.com
docs.google.com
"Engineers 3-10x more productive"
Citation needed.If this were generally true (of any technology X) the dollars would be flowing that way in an unstoppable torrent, and anyone using anything else would be the subject of ridicule and/or pity. It would be like writing custom websites in C.
Since that isn't happening, I have to take assertions like that with a sizable chunk of salt. The alternative would mean that there's a gigantic arbitrage opportunity that's being missed by a bunch of highly motivated people. So yeah, citation(s) please.
I started up with clj and I am trying kinda heavy arbitrage here :)
Managing a transition like this is far from trivial for a company facing a variety of immediate demands and constraints, even if it promises to pay dividends in the long run.
As far as I am concerned, they are all being deeply deceitful. If you make some "fact" up, and pawn it off as the truth, you are being dishonest.
Support for clojure's worldview is easy to find on the web. It comes both from the clojure community itself (see Rich Hickey's talks) and from the wider communities that clojure draws its ideas from (other functional languages, lisp, etc.) Decide for yourself if you find the arguments compelling. In my experience, the clojure community is not interested in promoting clojure for reasons of tribalism or vanity, but because they can indeed use it to produce better work faster.
Example needed. Cascalog?
That's standard process for any language.
The question is: why should we assume that Clojure pays more/special dividends in the long run?
It depends on who you are. I recently used Clojure on a skunkworks feature for our product for which I had three days to complete. I am absolutely convinced that it was at least 3x smaller (LOC) and took me at least 1/3 of the time it would have taken in Java. I am an expert Java programmer and not a newbie to Clojure, but I still have to look up a lot of things.
The killer productivity feature of Clojure (LISPS and other languages) is the REPL. Trying things out, analyzing data structures, etc. is where I would have spent a ton of time in Java. Even if you're not an expert Clojure programmer, just using the REPL can save you tons of time.
So not necessarily disagreeing with you, but I also think that a non-expert in Clojure can still run circles around an expert Java programmer when considering productivity.
The workflow is very natural and you practically never have to restart anything. You can build up state in the application, see how things interact, reload functions add new functions, and so on. Using a debugger in Eclipse is a very pale imitation of this.
The problem with this of course is that when a company tries to switch their more mundane engineers to Clojure, the project will likely fail.
It's too bad that these top coders are so bad at mundane tasks like high-school-level statistics.
I've seen companies end up in inversion, which means that the most apparently productive engineers are the worst ones. It's a common effect in "design pattern" Java shops with all their Visitor and Factory and Vibrator and AbstractSingletonFactory patterns. It's not pretty. Good people are either taken badly (because they keep agitating for rewrites) or become disengaged and eventually leave or are fired.
* M7 Overview: http://www.mapr.com/products/mapr-editions/m7-edition
* Datasheet: http://www.mapr.com/Download-document/21-MapR-M7-Datasheet
* Benchmark: http://www.mapr.com/Download-document/52-MapR-M7-Performance...
* Docs: http://doc.mapr.com/display/MapR/M7+-+Native+Storage+for+Map...
* AWS Service: http://aws.amazon.com/elasticmapreduce/mapr/
- the management UI isn't as good as Cloudera Manager, or even Ambari in HDP2.0
- 3rd party support isn't there. If you want to use anything you find on GitHub, get ready to add support for MapRFS, and revert the API version back to 0.21
- there are bugs. Weird, specific bugs in the filesystem implementation which will bite you once every few weeks. This is one area where they lag the ASF project: many eyes do make these kind of things shallow. Their smaller install base and fewer developers means these things take a long time to notice and fix.
The MapR team is sharp and responsive. It's founded by ex-Googlers from the search-infrastructure team (http://www.wired.com/wiredenterprise/2011/12/ex-google-man/).
M7 Tables are designed to be a drop in for HBase, with better performance and without the HBase complexity (it's much easier to run M7 Tables as the primary datastore for online apps).
M7 Tables support and certification for several key projects is coming along...
Spark 0.7 already works with MapR M7 Tables with the Hive images that were released with the Eco-1310 (http://doc.mapr.com/display/components/Hive+Release+Notes, http://answers.mapr.com/questions/7803/shark-spark-over-mfs).
MapR is in the process of certifying Titan (https://github.com/thinkaurelius/titan/wiki), and it's going is going through final QA right now (https://groups.google.com/d/msg/aureliusgraphs/RTeFVssIvoI/m...).
Help?
The language, or its aficionado -- either way, specific technologies have made me, in my own estimation, multiple factors more productive. Yes, there's the learning curve, and understanding things that are not explicitly stated line by line throughout the code. But then, there's getting shit done.
Unfortunately, a lot of people, processes, and institutions get hung up at the sentence before last of that previous paragraph.
I also turned other people onto some useful technologies, such as pointing a consultant at some reporting software that my department didn't want to spring for but for which -- of course -- the outside consultant had budget. I heard from her a month or two later that it had greatly eased things and turned her into a sort of reporting superhero.
Throughout my career, I've seen people who, both on their own as well as through dint of better technology awareness and selection, have been multiple factors more productive than their coworkers.
And yes, often they are fighting the trend and significant inertia, rather than being embraced.
The line on slide 111, "Engineers 3-10x more productive, smaller teams", is probably in reference to...
Slide 16: "Code is typically 3-10x smaller when written in Clojure."
Slide 110: "3-10x less code. Limiting factor in programming speed is essential complexity of the problem, not typing."
I have to take assertions like that with a sizable chunk of salt. The alternative would mean that there's a gigantic arbitrage opportunity that's being missed by a bunch of highly motivated people.
That there is a "a gigantic arbitrage opportunity being missed" is essentially the thesis of the talk.
He states the reason why (Clojure is cloaked in 50 years of Lisp misconceptions) on slide 21: "Lisp is an old weird AI language no one uses anymore. It's so slow it requires a supercomputer. It's impossible to hire people who know how to use it. Functional programming has been proven impractical. Also, parentheses."
The body of the talk is designed to dispel these beliefs.
Oh, it's a perfectly plausible number. It increases the productivity of each developer by a factor of 3 to 10 and also increases the maintenance costs by 3^n_engineers or 10^n_engineers. This seems to be the tradeoff that startups make.
Lisp has a bad reputation compared to what it is. People think it's impractical, that Lispers are arrogant (due to a few vocal but influential people in the Lisp community) and that it's archaic or weird. I've addressed those perceptions, but they're out there. Clojure is, in fact, a pretty damn practical language.
Now, the arbitrage argument: in larger companies, the concerns aren't engineer productivity so much as appearances. For a middle-manager to launch a meaningful Clojure/Lisp initiative would be to put himself out there in a major way, and since programmer productivity is only one piece of a much larger system, it might not have that big an impact on the company as a whole. It might not be worth it. (Would Google's market cap go up 3-10x if it replaced Java with Clojure? Almost certainly not. Maybe the fair value would improve by 1.05x on fundamentals, which would be drowned out by month-to-month volatility.) On the other hand, startups generally can't afford (or don't think they can afford) to experiment with newer, quirkier languages. VC-funded startups tend (surprisingly?) to have stodgy closed-allocation work cultures and boring tech stacks because they're expected to allocate 100% of the "risk allowance" to one department: business-model risk. That's not to say that there aren't other kinds of companies that can (and, in some cases, do) use more innovative tools; but the two dominant cultural forces (VC startups and large corporations) in technology don't favor it.
For the large companies, I'll admit that there's an Amdahl's Law sort of effect at play. Let's say that you improve productivity of engineers by 3-10x. Does that "3x" the whole company? As I alluded to for Google, probably not. It makes something else the limiting factor. For most firms, using the wrong programming languages is nowhere near their top problem. To use Google as the example, it might deserve a 5% bump on market cap if it included Clojure (a small gain compared to monthly volatility, so small that no one could prove causality and take credit) on the white-list but the fair value would go up 50-200% (again, on fundamentals, as I can't predict investor opinion) if it implemented open allocation. Programming language innovation just isn't the top priority for most companies. But for an individual developer, the advantage conferred by a powerful language can be pretty serious.
People choose what they work on. No "headcount" numbers that have to be agreed upon by people far away from the actual work. It's the one thing Google could still do at this point that would 2-3x the company.
EDIT: (yes, being a little cheeky because as we know the physical time programming isn't everything in building a website)
Your visual approach to explaining macros with arrows to demonstrate the substitutions also really helped me to grok them in a way I haven't been able to previously. They are actually quite simple aren't they? It's basically the same idea as html templating, but outputs code instead of markup.
I'd love to see you get more in depth on some of the headier topics--core.logic, monads, storm/hadoop interop, etc. You seem to have a gift for making difficult concepts approachable.
In fact, common practice in Clojure is to define a your macros in terms of a backing function:
(defn foo-fn [body]
(fancy stuff here that probably uses syntax-quote somewhere))
(defmacro foo [& body]
(foo-fn body))
Clojure's style of macro system is known as a "procedural" macro system because the macros can be any arbitrary procedures which returns code as data. There are other types of macro systems, like Scheme's syntax-rules, which are more directly embrace the fact that most macros are tree rewrites.Since I have never programmed much in Java (I went from c++ to ruby!), could someone tell me where the gains are coming from ?
I know that eliminating the setters and getters (and the private/protected/etc system) would eliminate a lot of code, but I dont understand if it would be that much.
Possibly, I'm also trying to understand if they would have gotten similar improvements in kloc if they had switched to.. ruby/python for instance.
The REPL made the first week of exploring the problem and solution space really effective, and even as a node guy I was impressed with what could be done.
I can say that there is definitely a big productivity boost, but as others have said it isn't purely the language, but rather thinking about the problem in a completely new way that really did it. I do credit clojure though with giving our engineers the ability to think differently, as that is often the hardest part.
There was a comment I made in a speech recently about functional programming being frictionless for content management system design, this is what I was alluding to.
I don't want to start a flame war, but we built an earlier version in ruby (with one of the best OO guys I know leading it), and it was much more complex through attempting to model our home page as a set of inter related objects, using visitor patterns to traverse etc., than the clojure version.
Could you comment a bit more on the interaction of functional programming to content management ? Intuitively, it feels to me that a lot of it has to do with the NOSQL-like data model of elasticsearch. Being a lisp beginner, I feel that a visitor pattern is very analogous to "map" in functional programming - again, without all the OO getter/setter functions (e.g. "accept", "visit").
A functional map is definitely analogous to a visitor pattern, but don't underestimate how much of a productivity boost arrives by being able to see all of the code in a small set of terse statements in one place, vs having a set of fairly abstract classes with accept/visit scattered all over the place.
We just found that the OO solution resulted in more code and it was more difficult to hold the resulting model in your head as the number of things that could be visited grew - we run a very big site.
The other big enabler vs a traditional CMS approach is that we have a very clear separation between the part of our stack that allows editors to create content, and the part that renders it (connected via messaging) - so we aren't mixing r/w domains and our rendering pipeline isn't burdened with the additional complexity of having to understand how content changes, it just renders what it is given as fast as it can.
Additionally, the abstraction features Java does offer are implemented with some heavy language syntax, and often can't be generated at runtime or pre-compile time, at least not easily, and so there's a limit to the abstraction, even taking into account Java Generics. That's something where homoiconic languages like Clojure have a particular advantage.
As a result, abstracting things in these ways (which in other languages is incredibly common) gets to be painfully verbose. Often, things that would be beautifully abstracted in these ways are just left unabstracted (as in-line boilerplate) - the verbosity introduced makes the code less readable, rather than more, and so there's a stigma against "over-abstracted" code. The result is that code that does, or could, make use of these things takes exceedingly more code in Java than in a language like Clojure. Of course, conventions in Java of, e.g., giving each curly brace its own line aren't helping its case in line counts, either.
My comment is basically a free-association from this.
In C and Java both (and, um, CSS), the people I've encountered seem to strongly prefer giving each matched pair of curly braces one line (that is, the opening { doesn't get its own line, but the closing } does).
In lisps (to my knowledge) it's more normal to have all your closing )s stuck together at the end of the previous line. Using a clump of )))))s to discern exactly which scope you're in afterwards is tricky (I'm pretty sure that's exactly the "problem" that the C/Java style is trying to solve), so you look at the indentation instead.
Python formalized the indentation-is-scope paradigm, which means a malicious programmer can't trick you into believing you're looking at a different scope than you are, but my Python code always ends up being a lot taller than I feel it should be, so I have a lingering sense that Python took it a little too far. It turns out that I occasionally appreciate the option you get with lisps to put a short bit of code all on one line and mark the parse tree with parens instead of with line-breaks-plus-indentation.
(All that said, I do like Python a lot.)
I personally hate the opening { stuck on the end of the line in C/Java. For me it goes on a line on its own pretty much every time.
I've lost count of the amount of times there's been a subtle bug introduced by incorrect scope as a result of a { being missed from the end of a line and not being noticed due to the code being formatted as if it was there.
With a { sat on its own, directly lining up with the }, that's pretty much impossible to miss.
It's an abomination.
Hopefully the formatting will work for this -
For example,
if (isOK)
for(thing in list
{
doSomething(thing);
}
}
Screams out to me at very first glance that I've missed a {,whereas
if (isOK)
for(thing in list){
doSomething(thing);
}
}
needs me to scan to the end of each conditional line to see where the problem is.As for closing braces, I associate them with the start of the statement itself (the if and for) and not the opening brace, assuming the indentation is consistent.
I'm not arguing one is necessarily more right than the other - just that I prefer the way considered less right by consensus.
The argument about taking up less space, I get - although given the massive monitors that we all have these days, that seems far less of a consideration than when I used to work on 20-line terminals.
What I just genuinely struggle to understand is how it's clearer (and if I managed to understand, it might help me parse other peoples' code).
Let me turn my code into something that actually has a matching amount of braces
while (readLine){
if (isOK)
loadSomething();
for(thing in list){
doSomething(thing);
}
}
versus while(readLine)
{
if (isOK)
loadSomething();
for(thing in list)
{
doSomething(thing);
}
}
If I was quickly parsing the first code, I'd assume everything was fine and that the first } was closing the if(ok). To spot the defect, I have to scroll up, find the matching control statement and check to the end of its line to see whether it had a {.With second one, even the most rudamentary scan tells me that there's an opening and a closing brace that don't match up. All I have to do is scroll up and see whether there's a matching { at the same indentation.
I'm not saying you're wrong - if you are, most people who write coding articles, or code that I have to look at, are also wrong. But I would love to know what it is that other people can see easier/quicker in the first code than they can in the second in.
Another handy tool is an editor with rainbow delimiters. This feature changes the colour of each matched pair of parentheses so that they can be seen at a glance.
There's really no excuse not to, since refactoring functional code tends to be as simple as taking a node in a tree and moving it out.
In Java, if you have a class containing a function which itself contains an if-statement containing multiple lines. You will have three lines at the end of the file containing nothing but }. There is no reason you couldn't clump those together and thus end the last statement in your function with }}}.
The difference is, in Java it's good practise to give each } a seperate line. In Lisp, most people prefer to clump their ) together.
Also, you could easily end a function with alot of )))))).
(defn unique-large-squares [list-of-nums] (count (unique (filter #(> % 100) (map #(* % %) list-of-nums)))))
Of course, if the clump of ) are off-putting, you could always use ->
(defn unique-large-squares [list-of-nums] (-> list-of-nums (map #(* % %)) (filter #(> % 100)) (unique) (count)))
`)))))` at the end of a function doesn't matter. The function's over. Even if you needed to make a change that would break the clump up, you generally navigate it from the opening side.
But if it's at the end of a fat true-expression of an if-statement, you probably have to add a `;; x is false` comment to remind yourself what's going on by the time you get to the false-expression.
Just like in Python when you get to an `else:` yet you have to scroll up just to find the matching `if` because somebody decided to roll their own SOAP client on the true path.
Aside from the fact that if you're color blind then apparently you're stuck with all the )))))))s.
For instance, you'll often see a "Person" class definition with getters, setters around the .adds collection function. The idea is to encapsulate the collections as much as possible so that if it changes down the road, nothing else is affected but that simple method. In lisp, however, you'd probably just (let (people '("tom" "john"))) and be done with it. I'm obviously exaggerating, but hopefully you get my point. It's similar in Python where I use dicts all the time, but feel bad using it in Java or C++ without abstracting or encapsulating it.
It's not so much a syntax issue (even though clojure syntax is less verbose than Java) but mostly the mentality behind the idioms IMHO.
In a functional program, I'll just create the function and pass it around anonymously if needed. The function will in itself will likely be simpler than the Java equivalent and stateless.
There will also be less DTO type class code for carrying around dumb collections of data, replaced with simple records and lists.
I'm not at the stage where functional programming has really clicked for me, but after writing some Clojure and Haskell recently, the sheer amount of code you have to type in in Java to express yourself is really starting to bug me!
As an aside, I loved the chrono trigger reference! I was actually listening to some of its music as I viewed the slides.
I know this is old hat for the FP community, but it's worth mentioning that the dot product would be normally be written as (reduce + (map * xs ys)) (or something similar) for the sake of readers scared by the loop acc pattern.
People want to believe the world is simple, and that learning one PL is enough. Once you know Java, why learn another one? Either they're all the same, or they're so radically different they must be weak in some critical way.
When you grok Lisp, and realize that it is actually practical, you realize that you've only scratched the surface of the PL problem... and that's scary for a lot of people, especially as there's a tendency to overestimate the barriers between languages. (The Internet runs on components written on all sorts of different languages.)
it's worth mentioning that the dot product would be normally be written as (reduce + (map xs ys))*
Yes, I had that thought, too.
In fact, that formulation is too slow for, say, large-scale ML. I've been getting a lot of mileage out of Prismatic's hiphip library... and I really look forward to, about 5 years from now, when Clojure is as mature for numeric programming and ML as Python is with Numpy, Scipy, Numba et al.
Clojure is a Lisp. Lisp based languages are great.
However:
One of the problems with clojure - or rather with its home or ecosystem - is the fact that it requires a very high activation energy to get going. Grasp the concept of functionial programming, cc/call, macros, totally different syntax than your previous imperative language of choice, and last but not the giant blob that is called Java platform with all the traps regarding project management, IDEs, building, compiling, deploying etc. I know that there are great tools such an Leiningen or LightTable, but they only make the whole process of transition more manageable.
Now, I know that Java is a huge benefit for all that want to make use of its gazillion tools. But if You are not into Java, then Clojure might give you some hickups.
In comparison to Clojure, Python also allows for some functional programming, gives the eager disciple an easy going start. Most of libraries are written in Python (or exist in a fast, a C-esque implementation) and are very easy to grasp. I can not say that for the Java enviroment Clojure has been born into.
I frown at java lingo error tracebacks in the REPL, and to bring a external Java library into play is even more problematic. Any thoughts on this how to remedy this problem without getting involved into Java?
I wish there would be some kind of Index of how to use certain Java libraries from Clojure, or an index of Clojure wrapping packages. It might make life a bit easier.
Finally, I claim that for now, I am quite happy with my choice to migrate from Clojure to Chicken Scheme/picolisp. You can get quite a bunch of Clojure data types from the good package repository. It compiles without setting your hair on fire. And it is really simple, as the language basics are small.
I will keep an eye on Clojure. but I must say that Julia is as appealing to me when it comes to the choice of future language.
Can you recommend a good picolisp resource?
I'm looking for another language with similar philosophy to Clojure's, but with a better ecosystem.
A. Luck out and find it immediately.
B. Get directed to it by someone more experienced.
C. Chase a suboptimal solution because you don't know better. You simply don't know there's an easier workflow. You don't know you can eval code within an editor. You don't know there are tools like paredit or how they'd help you.
For toy webapps, it's good to know these incantations:
lein new compojure myapp (creates webapp skeleton)
lein ring server (starts embedded server for dev)
Here's the live demo of a dumb app I threw together to take an IRC joke too far: http://www.danneu.com/spinners/And here's the Clojure code: https://github.com/danneu/spinners-as-a-service/blob/master/...
To deploy it, I rsync the repo to a remote server, run `lein uberjar` remotely, and launch the uberjar.
That repo shows how to use Compojure for routing, Hiccup for html, Clojurescript, and a few incantations (like `:genclass`) to get it working.
Why not use Scala insead?
scala
if (x > 0) ...
clojure if (> x 0) ...
The clojure syntax here is a bit absurd, IMHO.I agree that it is uncommon and take getting used to, but it does have the advantage of being consistent, and consistency and lack of special cases is a part of simplicity.
I think that the concept of standards is worthy of consideration. While '>' is an operator in scala and other languages, it's also an operator in basic mathematics. And in basic math, we're taught "if x is greater than zero" using the notation of "if x > 0" (parentheses notwithstanding.)
It's only consistent in terms of how clojure presents it, but it's inconsistent with treatment elsewhere. Consistency does go to simplicity, but if it takes some "getting used to", it can't be all that simple.
For example, how would you express the "between?" in infix notation? In Clojure we can use the same function - "(> 1 x 0)".
I do agree that Clojure way takes some getting used to.
Well, engineers using scientific calculators handled polish notation (and reverse polish notation, like 3 4 + for 3 + 4) just fine for half a century or so...
In fact, it has been with us in programming for over 6 decades, and is a classic mathematical syntax called Polish Notation ( http://en.wikipedia.org/wiki/Polish_notation ).
For one, it makes all method invocations the same: the method name followed by the arguments. Here the method is operator plus (addition).
I find it "absurd" in that it requires adaptation to a form of syntax that's more niche than anything. I don't see that adding to the argument of simplicity in this particular scenario.
I'd guess that, for you, Clojure _wouldn't_ have the same kind of efficiency that some others see. Lisp, in general, appeals to people who think "A is really the same thing as B. Cool!" They see treating all functions the same as a really worthwhile thing, in and of itself. Others, such as yourself, aren't really excited by that. It's a style thing.
Fanatical generalization can be a really effective trait in some circumstances. A small team of generalizers working on a reasonably-defined problem (such as a re-implementation) can turn out amazingly simple and compact code, since they tend to factor out common things.
On the other hand, a generalizer might not be as tactically-focused as someone else. A tactical person might be more inclined to make a surgical change, whereas a generalizer might wind up with a "toolbox enhancement".
A tactical person is going to get more mileage out of tools that already take care of a lot of common cases, and do them in common ways. A generalizer will do better with tools that are more "meta".
Because this is just syntax, "A 'looks' the same as B. Cool!" is a more definitive statement. After all, it's just getting compiled/translated to JVM byte code anyway.
Efficiency is an entirely different conversation and tangential to the one we've been having regarding syntax and simplicity. Nobody has asked to this point, but I have no problem with Clojure's syntax structure. I find it very compact, I like the explicitness of parentheses, and like that it works in the JVM. (Disclaimer: I've not deployed any Clojure-based code in a production environment, so my own experience is limited.)
I also find that it's syntax has its own quirks, much like every other language. And while some things 'look' the same in Clojure, other things don't -- and that's perfectly ok. It's relatively consistent enough that the syntax logically points to its idioms.
But I stand by my original comment: it's only as simple as the observer makes it out to be. I don't find the syntax of Clojure more or less simple than many other languages.
- They are variadic functions, they work on a range of inputs. - Their names are valid identifiers, which allows for function names like list->vector - Precense is fairly self-evident. 2 * 2 / 5 - 1 vs (- (* 2 (/ 2 5)) 1). You could add parenthesees to the first, and most would, Lisp just forces you to. - They are consistent, a function is the first element of a list, no matter what - Closely related to the above point, they make writing macroes easier. Imagine if macroes had to take infix operators into account. Certain macroes would have to scan the syntax they receive for the presense of operators, or you would have to create special macroes for operators... - You would need special syntax for passing operators as values to other functions. ((dummy) < 5) ;; What should happen here if dummy returns another function instead of something orderable?
Now the next question is: where do I need that for? Just let it soak in for a while: it is surprising how your solutions change if your tool works differently.
I've been busy with Scala for some time now, but the OO aspect also dominates the FP part. And that OO part is huge: traditional classes, case classes, traits (which are occasionally used standalone) static functionality not in the class but factored out in an object, structural typing just to name some.
There are many aspects I like of Scala, but simplicity is not among them. In teams you will have to have strong communication if you do not want to limit yourself to a subset of the language ("no fp" for instance)
(defmacro ord-compare [a ord b]
`(if (or (= > ~ord) (= < ~ord)) (~ord ~a ~b) "Use > or < to compare."))
(ord-compare 3 > 2)
Edit: there's also incanter.inflix, which will translate inflix notation into clojure like notation.https://github.com/liebke/incanter/blob/e1235cf9ffa2e528823e...
Check out the tests for how to use it:
https://github.com/liebke/incanter/blob/aa71f1135c3beb7bf7a4...
A good example:
; $= translates inflix to prefix notation.
($= 3 <= (5 * 2/7)) ;will give you false. (< 1 2 3 4 5 6)
;; true
Any function can also take arguments from a list, (apply < (range 1000))
;; true
Prefix notation really comes into it's own when you start looking at multiple arity functions. Please don't confuse unfamiliarity with absurdity.Although I think I could create a function in Scala that permits the same thing, yes? Mostly the arbitrary operands or range reference imply recursion & iteration, which I believe I could implement easily. (Check me if I'm wrong here, I might be missing something.)
I wouldn't have suggested that, except that Clojure (as I understand it) also encourages that one can "expand" the language. I would see adding this capability as a Scala function in the same light.
Which is basically the same as (foo a b) except the ( if one identifier later.
I've often seen stuff like this in languages without operator overloading: a.add(b.multiply(c) d.subtract(5)) and nobody complains about that, but a lot of people are hung up about (add a (multiply b c) (subtract d 5)) which is almost the exact same thing. Of course, in Lisp-like languages, you would be able to redefine functions, s it would actually look like this: (+ a (* b c) (- d 5))
I don't get why people have such big complaints about syntax. Whatever you are used to is easier to read. Obviously! But its not hard and does not take long to get used to this.
So once you are used to it, Lisp is simpler because it has one single rule that is followed by every language construct: (function params) - in other languages you have all kinds of flow control statements with different rules (if, else if, while, for, switch.. all have different rules). Then theres function calls and method calls. Precedence. That's a lot to have to remember.
Pros for Clojure:
* Faster code -> result cycle. No need for compilation (except for AOT-compiling releases).
* Absence of static typing helps in some of the domains, e.g. web applications. We have successfully used Prismatic's Schema[1] in places where a stable data interchange format was needed.
* Binary compatibility. No need to recompile libraries for different Clojure versions.
* Community oriented towards simplification. People mostly try to mimic Rich Hickey and Clojure.core development approach.
* Orientation towards small libraries. I haven't yet had a need to use a framework written in Clojure (although Pedestal[2] seems interesting).
[1] https://github.com/Prismatic/schema [2] http://pedestal.io/
Type classes can be mimicked via multimethods or protocols.
Is learning clojure enough if I would like to write lisp in future?
Since clojure is lisp (although not common lisp or any other non-clojure variation like Scheme), I would have to answer yes.
Also, syntactically Scala is a lot more complicated than lisp. It's a bit closer to Java, but that doesn't make it simpler. Just more familiar.
When evaluating language tradeoffs the scala community values power more and the clojure community values simplicity more.
Scala wants to provide you with the most powerful language possible. Clojure wants to make it easy for you to mold your own language.
Scala language tooling works at compile-time and analyses the language statically. Clojure language tooling connects to a running environment and uses introspection. Scala has much better static checking and clojure has much better introspection. While both languages have a repl, the clojure community puts much more emphasis on live, interactive programming.
Clojures syntactic extension mechanisms are much simpler, being based on sexps. Scalas are powerful (eg can access the lexical environment) but much more heavy-weight.
Clojure has run-time eval. This makes it possible to do eg domain-specific jit (eg compiling DSLs -> clojure code -> java bytecode on the fly). Scala has a run-time interpreter which I haven't used but is reputed to be slow.
I haven't yet explored non-jvm backends for scala but I suspect that clojure will eventually dominate on that front for two reasons: 1) when clojure-in-clojure is finished porting clojure to a new platform will be far easier than scala and 2) clojure was designed from the beginning to be a parasitic language and delegates many features to the underlying platform.
Scala breaks backwards compatibility much more often than clojure. Whether this is a pro or con is up for debate. There are lots of small niggling things in clojure I would like to change but on the other hand maintaining scala code across compiler updates is a pain in the ass.
Personally, I believe that the number one problem a language needs to address is managing complexity. The clojure community largely seems to get that and is driving for simple, orthogonal language features and libraries to an extent that I've not seen in any other community (eg http://blog.getprismatic.com/blog/2012/10/1/prismatics-graph...). In addition, the most exciting research I've seen on that front (eg http://www.vpri.org/pdf/tr2011004_steps11.pdf http://boom.cs.berkeley.edu/ ) and most of my favorite tools rely on powerful introspection and runtime code generation. I think Yegge describes this better than I can - http://steve-yegge.blogspot.co.uk/2007/01/pinocchio-problem....
I would use Scala for a personal project where I felt I needed compiler-time typing: I was writing something for the ages, or where bugs might be truly intolerable (say, high-frequency trading) but code would remain small. I wouldn't recommend it for a huge project, though. (Then again, I generally wouldn't recommend huge projects.)
Scala tends to fall down on large projects, especially if the developers aren't skilled. Cyclical dependencies (yes, I know they shouldn't exist, but they will if you have a team of 25+ engineers and a wide skill spectrum) defeat incremental compilation, which matters when your compile speed is ~500LoC/second (Scala's compiler is very powerful). Also, SBT is a nightmare. I haven't used Scala's macro system but I can't imagine it being as clean as Clojure's.
I like Scala on its terms alone, even if I've seen it go wrong on large codebases. (Java has the same issues, but it has tools that rescue you. It's an ugly hackish thing, to rely on tools to deal with code messes; but they're there.) I like static typing (at least, the theory that comes from it.) However, I tend to think that what most programmers really want when they say they want "static typing" is something more like Prismatic's Schema: runtime checks that can be turned on or off (performance) as needed.
I think Clojure's easier to read and to write. It just looks harder, because people exaggerate the parentheses problem, which is not much of one at all. If anything, the only thing that's somewhat hard to explain to newcomers is quoting (e.g. why '(1 2 3) returns (1 2 3) at REPL but (1 2 3) is an error). The quotes were the hardest thing for me to get right when I started in Lisp.
I'm getting tired of statements like this. I've been using Clojure for a couple of years now. I got over the () "issue" after a couple of weeks, once I discovered Counterclockwise for Eclipse (and, eventually, Emacs paredit or smartparens). You just don't notice them after a short period.
In general, editors that "understand" Lisp-like syntax are more powerful than other code editors. Being able to select forms - anything enclosed in a (), {} or [] - with a key combination and move them easily around the hierarchy (also see barfage & slurpage in the paredit cheatsheet: http://www.emacswiki.org/emacs/PareditCheatsheet) makes editing code faster than other languages.
As for the "easy to read" argument, I now find Clojure easier to read than, say, Java because there's generally less of it.
however, i have to differ with you completely regarding scala being easier to read. as someone who regularly works with scala code i find it incredibly difficult to read in comparison to clojure. Lisp syntax is different from what most people are used to but is very simple; scala looks more like the syntax that people are used to, but is deceptively quite different, and is quite complex.
Unless you use a buffer implementation, channels have no "placeness", you're not mutating/adding to a queue by parking a go block.
I liked everything else.
core.async has state (when buffers are used, in particular) but state is not exactly the same thing as mutability. Producers and consumers don't have unconstrained access to channels, in the way that users of a mutable cell (a Clojure atom, a ref cell, or just a variable in many languages) can clobber it at will.
Likewise (although I didn't get into this) state doesn't necessarily violate referential transparency. Memoization uses state as an optimization, but doesn't interfere with RT.
Boy do Haskell users ride that one hard.
Wish there were more though!
That might change. Clojure's been making some pretty impressive in-roads into the enterprise.
At this year's Conj, there were a fair number of companies hiring. Staples Innovation Labs is apparently hiring a lot of Clojure people.
What part of the world are you in?
Ah, yeah, I really wanted to go to Conj, but only found out about it last minute. I'm in San Francisco.
It's not that there are no companies using Clojure, it's more that the companies where I do want to work, don't want to use it.
When I mention it in an interview or something they kind of give me a funny look like they hope I am not one of those LISP people. I mean I can see where they're coming from. It's a big risk to let someone write in a language you don't know much about, and that you don't know if you'll be able to hire for in the future.
And at the places where they are feeling a bit adventurous, everyone seems to be leaning towards Go :(
Oh well, I can still use it for all my side projects until it gains more popularity I suppose. It really is such fun to use. I only started 2 months ago and I have been having the best time of it.
I'd add adjectives (including adverbs), which is the metadata on the nouns and verbs.
Adjectives are properties or classes of things, like Numeric or Closeable (with-open pattern) or Monad. The Haskell solution is type classes. The Java solution is OOP. The Erlang solution (fairly similar) is the actor model, which is the inspiration for OOP's principle of locally interpreted functions/methods (as opposed to global function definitions). OCaml's is functors, which are extremely powerful but hard for most people to use.
Just in case you don't know: Restrictive clauses limit the possible meaning of a preceding subject, whereas non-restrictive clauses tell something about a preceding subject, but do not limit its meaning.
Example of restrictive use: The suspect in the lineup who has red hair committed the crime.
Example of non-restrictive use: The suspect in the lineup, who owns a red car, committed the crime.
from direct work experience in building complex systems in clojure....I agree with all the statements made in this document...
I am a better developer because of it and will look at things differently if I need to pick up java or scala again..
and I will also make sure to always "get in the hammock" before writing a line of code..
[1] https://groups.google.com/forum/#!msg/comp.lang.lisp/L5dZ-j6...