The hard part of Clojure really boils down to one thing: you do not have an assignment operator. If you realize you must now program without that, how would you do that? Answering that question in concrete cases is your only real problem.
Other things, like the parens, well, you stop even noticing them after your first few hours. When you first start, just move the paren one word to the left from where you're used to and you're good to go. The syntax after that is so simple, you will find it liberating.
First, there seems to be at least two ways to do things: the verbose way and the succinct way. This creates more things beginners have to memorize.
Second, so many :keywords. Presumably some function/macro needed to be made more flexible and/or more succinct for certain circumstances so they add magical (from this beginner's POV) :keywords to make it translate their arguments in different ways. Clojure functions seem more like Unix commands rather than functions in most programming languages I'm used to.
And finally, an imperative programmer's tendency to create long functions. As a beginner my brain starts to shutoff once I encounter a Clojure function that reaches 5-10 lines. But 5-10 lines in an imperative language is pretty short.
Clojure is a simpler language, but because of that it doesn't benefit from the syntax highlighting more complex languages may have. This makes it more difficult (for me) to parse similarly lengthed Clojure programs. Of course similarly lengthed Clojure programs can do more than an imperative language, so it should probably be split into more functions, which would make it easier for me, as a beginner, to read.
I feel like people tout the succinctness of Clojure as a benefit because you can write shorter programs. I've come to think it's a benefit because you can section off more of your code into descriptive functions without exploding your code length, which make the program easier to read. When I start to use that succinctness to write less code it quickly becomes unreadable if I revisit it in a month.
As far as syntax highlighting is concerned, I find that using emacs helps a lot here. This is my `emacs.d` config.
https://github.com/nickbauman/emacs-dot-dee
This allows structural navigation for Clojure code. Good luck.
Except that you do have assignment. Even more so, every def is a Var, defn definitions themselves being vars that can be redefined, in true Lisp tradition and you also have atoms and you can use mutable arrays or any mutable collections you like, with people doing plenty of that. The emphasis on its simplicity is also misleading. For example Clojure developers pride themselves on how Clojure does not do OOP, except when it does of course, plenty of examples being in Clojure's standard library, starting from really basic things such as ISeq.
And this is actually confusing beginners that read introductions such as yours and I think it's doing Clojure a slight disservice, especially because this isn't defining what Clojure is or explaining why it is awesome.
I do agree with the sentiment. Just the other day I was trying to understand a piece of C# code that was written in a classic style, mutating variables and arrays in place to calculate something that could have been described as pure and very understandable expressions. And oh my god, it's as if I forgot how that was and I hated every minute of it.
I don't say and I don't see others saying "Clojure does not do OOP". If you notice this feel free to point this out; even ask me for support. Our community should be exemplary of keeping these things consistent. We all need to do our part.
As an example: C doesn't have the complication to the language of having "built in" types for hashes or lists. This makes the language easier, since you don't have to learn the extra syntax and grow the mental model of how they were implemented. On the other hand, if you need a hash or list - you need to create your own (or adopt someone else's implementation via a library).
C is a simple and powerful language, but there's so much you have to do yourself, that it's easy to get something wrong.
Clojure (and lisps in general) hide their complexity in macros. This level of abstraction can be great, until you have to dive into the macro and see exactly how it's manipulating your code. Or write your own and troubleshoot the resulting dynamic code.
You can be productive in clojure, I think, without being extremely fluent. But Clojure does tend to some perl-esque terseness. Browsing down this page (http://clojure.org/reader) everything is fine until you start getting into macro characters, and then the dispatch macro, and then the regex dispatch macro. I think you could write perfectly fine clojure code without knowing the details of all of these, but it can be frustrating to not know if your code is idiomatic clojure or merely badly translated from another language.
People should learn first through Racket and its awesome DrRacket. I wish I first learned programming in Racket and not Basic and Assembly.
My kids will go through Racket in a few years.
Nah. You have `let` which is exactly that.
While Clojure foundered a bit after its start in the race to become Java.next I think that what has ended up saving it, or at least given it new life that it really needed, is a particular combination that is not even mentioned anywhere in the article: Clojurescript and React wrappers like Om and Reagent. I know more people considering Clojure(script) as a path to a combined web app and mobile app (via React-native) than I do people looking at Clojure to power the back-end.
Very seldom do classic companies ask for anything other than JavaScript on the browser or Java on the JVM.
[0] Same applies to other FP languages on the JVM.
Java and Clojure mix very well in projects: set up a separate Java source path and let lein build everything.
[1] you can grab a free copy at http://markwatson.com/opencontent_data/book_java.pdf - it is my Java Semantic Web book.
http://www.lispcast.com/solid-principles-in-clojure
which elaborates on SOLID OO design in Clojure and provides some code examples. For example there's a pretty clear example of the right way to apply SRP to a functional paradigm.
I'd interpret it as you need SOLID to do successful OO (required but not sufficient), but using as much SOLID as reasonably possible under any paradigm also happens to result in good/better software. In that way there can be a lot of confusion about what is OO and what is merely usually found nearby OO but isn't OO specific.
I think the value of SOLID is that it gives you tools for thinking about your code.
I think there is lots of room for a critique and even a debunking of SOLID. Indeed, Kevin Henney has done just that. http://yowconference.com.au/slides/yow2013/Henney-SOLIDDecon...
Though I already had one foot in that realm with playing around with Racket and learning Scheme in college.
"obvious power of code becoming data."
Many languages have eval() where data can be treated as code.
Compare the the code size in Java and Clojure.
If that is not enough, do the same thing but start with java objects (and their clojure equivalent: a hashmap) for some given object/map property.
EDIT: And if that is not enough, use as property of the object a string, defined only during run-time by a user input.
When I was first learning Clojure I stumbled on a "lack of good documentation" in third party libraries. I'd google around for something that solved the problem I was trying to solve so I wouldn't reinvent the wheel. I'd find, say, a github repo that had a couple of sentences in its README that purported to solve my problem and then nothing else. What the hell, I thought; why no decent doc? Then I realized: the solution was implemented in 40 lines of Clojure. Reading the source was the fastest way to figure it out.
It still happens to me. Every time it does, I have this warm feeling of investing in something of great value.
I'm trying to implement it in Kotlin and am curious how it would compare.
Almost all currently used languages have some functional programming support. Many "modern" languages are functional in nature, even if it's well hidden behind syntax sugar.
Lisps, and code-as-data, is different, in that it's about compile-time meta-programming and not runtime execution model. There are non-lisp languages which offer similar capabilities, see Elixir and Nimrod for some recent examples.
Anyway, if you want to understand practical advantages of FP you should just use it in practice. It shouldn't really come as a surprise that you can't see practical benefits if you only studied a bit of theory...
- functional programming (Haskell, Scheme, Clojure) which favors recursion and stateless functions
- homoiconicity (code=data) (all Lisps)
These two concepts are completely orthogonal, and there are many Lisps such as Common Lisp, Emacs Lisp where functional programming style is not encouraged. Most of the code in these languages can hardly be called functional.
Conversely, not all functional programming languages are Lisps or homoiconic, in fact most of them aren't.
I will just address this point, which IMHO is orthogonal to your question about the benefits of functional programming. Let me give you a simple example of macro: a macro print-variable that takes a variable and prints: "$variable = $value", where $variable is the variable name and $value its corresponding value. I wrote it on my Clojure REPL, and run it that way:
user> (def x 4)
#'user/x
user> (print-variable x)
x = 4
nil
In a language without macros, the function print-variable wouldn't have access to the string "x" once x has been defined. In a language with eval, you could do something like: def print-variable(variable_name):
value = eval(variable_name)
eval("print("+variable_name+"="+value+")")
But you would have to call that function with a string, which is not as elegant and can lead to errors as the string could be misspelled.Now, I will show you the code of the macro in Clojure:
(defmacro print-variable [variable]
`(println '~variable "=" ~variable))
What is does is take the variable you want to print, and defer its evaluation (~variable) only when you want to know what value is assigned to that variable. In the meantime, it can get the name of the variable ('~variable).Here is what it does when I expand the macro:
user> (macroexpand '(print-variable x))
(clojure.core/println (quote x) "=" x)
The clojure compiler transforms the macro into the expanded code, and then injects it into the rest of the code.Hope this helps.
Macros let you avoid this kind of problems when meta-programming (but then they bring their own problems: hygiene, for example).
The main point of the article, was that the junior programmer was right: well structured, self-documenting code is always better than fast code. If it ends up being too slow, and (in the case of C) can't be fixed with "inline" and "-O2", then, and only then, move towards a different, hopefully more efficient solution.
Now, obviously, writing functional-style C isn't the only (or perhaps even the best) way of writing structural, clean, C code.
But functional composition, especially with help from the underlying programming language, can be compact, and very easy to reason about.
Never mind the fact that approximately half of Haskell (and some clojure?) programmers appear to think that "f a b" is more readable than "scaleVector Vector Factor". Conciseness can be a weakness as well as a strength.
Not a lot of aspects of functional programming are tied to the code is data idea (formally called homoiconicity). However when writing Clojure, the user is actually inputting Clojure data structures. Something I've noticed is structural navigation inside the editor has beneficial. I can edit Clojure code so much faster than any algol-family (C-like) language I've used. And while I find it important to spend more time thinking than typing, it's easier for me to stay in flow when the code is so malleable.
Once you've convinced yourself of that and you look at Clojure through that lens you will find immense power in that language, as everything is built around data transformations.
I do think the move away from data processors as a title is more of an ego thing...none of us probably wants to be called a data processor.
- Functional programming style tends to make your programs easier to reason about, as it avoids state/mutation. This also makes testing your programs much easier, and can also make concurrency easier.
- It's a different way of thinking. Some problems are much easier to solve in a functional fashion, some are much easier in a imperative fashion.
- Functional code can increase code re-usability as it decouples data from its operations
- A lot of functional languages have very advanced type systems compared to say, Java or C++. I'm personally a big fan of static typing and after learning F# I am sorely missing its type system in C#
That's significantly less powerful if you lack structured ways to compose things together before evaling them.
Java 8 > Kotlin > Scala > Clojure
That's just my impression, especially if you're risk averse and want to make improvements as incrementally as possible. But I could be wrong. Anyone have a good counterexample?Another strong advantage is the development lifecycle. It's much tighter thanks to the live coding built right in. This should make it much faster to catch bugs or feel out new code. You can also use this to implement zero-downtime deploys and patching.