This is a great article. More articles in similar tone are needed to highlight how simple this language is. A big disservice to Clojure was probably done by a few early adopters of Clojure who hyped up the LISP heritage of the language to the extent it turned away C/java guys like myself: I recall reading somewhere that in order to learn Clojure , one had to master SICP and Scheme. That was a huge learning curve I did not have time or inclination for. However, once I waded into Clojure, I was amazed by how simple the language is really and how productive I could get; Clojure REPL is awesome . I still haven't mastered the language, I haven't mastered macros, protocols etc. and I bet my code is ghastly and non-idiomatic but I have still managed to write Clojure code that does what it is supposed to do in a highly concurrent workload.
I had the same experience. When I first heard about Clojure, one of the first things I learned was that it was a Lisp. But having read in numerous comments, blog posts etc. that "only the top percentile of programmers use Lisp", and since I don't consider myself to be anywhere near the top percentile, I felt that my programming chops might not be adequate enough to learn it.
So I put off learning Clojure for about a year or so. However, I grew more and more weary of Java's obvious shortcomings, the inherent bureaucratic nature of the language and lack of modern programming features (such was the situation at the time at least, things are starting to look better for Java nowadays) and started to look to other languages. I tried Scala. It didn't work out. I still wanted to leverage my existing knowledge of JVM and the whole Java ecosystem, so I turned to Clojure again. Also, having spent perhaps too much time on HN, I really wanted to see what that fuss about Lisp was all about.
Anyway, what I found out was that you do not, in fact, need to be a genius developer to learn Clojure. Actually, Clojure was everything I hoped for. It's dead simple. The syntax is minimal compared to some other languages. You may have heard other people say that learning Lisp can be an enlightening experience. Yes, there definitely are some enlightening moments, but not in the sense that you need to spend years meditating on something to be able to understand it. Read a good book, there are plenty of those around now, watch some of Hickey's talks, and you'll get it.
To summarize, here's my message to anybody who is thinking of learning Clojure - don't get discouraged and give up on Clojure before even trying to learn it just because it's a Lisp. It may seem strange and perhaps a little frightening at first, but once you spend some time with it, you'll get amazed at how wonderfully simple it really is, and how powerful it is precisely because of this simplicity.
since I don't consider myself to be anywhere near the top percentile, I felt that my programming chops might not be adequate enough to learn it.
See? The magic was within you all along.
:)
I wonder if the causation is confused, here. That is, you do not need to be a top percentile programmer to understand or use Lisp. You are -- or become -- a top percentile programmer because you've learned Lisp.
I don't know if the relationship is as direct as all that. But I do think that if you learn and internalize some of the lessons of Lisp, it will expose you to new ways of thinking about programming as well a programming problems, and this is correlated with being a good programmer.
One particular example: the close relationship between code and data in Lisp pulls aside the curtain a bit on some concepts which are more obscured in languages like Java or C++.
I don't know about Lisp making me a top-percentile programmer but I do know learning Lisp has improved my skills (not mastering, of course, but becoming comfortable reading & writing code in it). I also feel what I've read from SICP has helped massively too.
For one, recursion. I 'got' it as far as the fact it's a function calling itself but it was only through digesting Lisp books, writing lisp and talking about Lisp that I finally got it. SICP helped further with recursive-iterative stuff too - it doesn't just need to call itself to be recursive.
Another is functional programming.
There are many more but the point is that I could have learned all these concepts, mentioned or not, in other languages but it was the simplicity of Lisp that I feel allowed me to truly understand them. I also feel if I dedicated more time into Lisp, I'd get much more than just a new language out of it.
The reason for the hype may have been to leverage the rich literary tradition of LISP. Understanding LISPiness of Clojure probably depends upon that literature - there just aren't Clojure specific equivalents.
I didn't know about clojure-toolbox. That's pretty neat.
One thing though, regarding this page, is that you don't need to install clojure with brew. Leiningen takes care of all that... clojure is just a jar that's included in your project, aka a dependency, and Leiningen manages that. This lets you tie a specific version of clojure to that project, which is handy for some legacy projects that aren't maintained anymore.
Also, if you drop the brew references, then this becomes OS agnostic. Just go to the leiningen page on github[1] and it'll get you started: osx, windows, linux.
I develop with clojure on my mac and I've not brewed anything related to clojure.
You still need to install the JVM. Python/perl/ruby require installers because you need some platform-specific stuff for each. Running everything inside the JVM means you only need to ship what any arbitrary JVM library requires. In this case, its as simple as a .jar.
So Clojure has over (say) Ruby the feature that you don't have to install it. Yet you do have to install a JVM... How is installing a JVM better than installing any other interpreter or runtime?
This is the same advantage JRuby has in that Java developers don't have to convince someone in some chain of command about installing a new tool; it's just a jar file.
It's more of a plus if you already have a JVM in place.
The JVM tends to change less often than a language runtime, so you can use the JVM version that's packaged for your operating system, but still take advantage of the latest language runtime.
"How is installing a JVM better than installing any other interpreter or runtime?"
Maybe, just maybe, the fact that Clojure isn't exactly the only program on earth running on the JVM and that, hence, there's a probability p far from zero that the JVM is already installed on your system / on your users' systems!?
There's a good chance that a Perl interpreter is installed on any Linux system, but this is really an incredibly trivial reason to prefer a language. If you can't use (say) a ruby installer you are going to have even bigger problems building almost any kind of software.
True clojure assumes the existence of the JVM. However no other jvm language has gone with the language as library system which is a shame.
Also, I don't think anything would preclude non jvm hosted languages from doing something similar. I think it is a better solution than say virtualenv from python.
matthavener wrote: "Running everything inside the JVM means you only need to ship what any arbitrary JVM library requires. In this case, its as simple as a .jar."
Considering a .jar is a zipped directory tree, and a virtualenv is a directory tree, would you be happy if we zipped up virtualenvs and called them .par or something?
I'm not sure what "language as library" will mean if you are not installing a VM or interpreter such as the JVM.
I think the important difference between virtualenv and lein is not the implementation detail of whether it is a zipped file or whatever, but in how you use them.
If you run a python program with virtualenv who decides weather to use python2.5 python2.7 or python3? Is it the author of the program? No, typically it is the user of the program who decides by symlinking /usr/bin/python
If you run a clojure program "lein run" who decides weather to use clojure1.3 clojure1.4 or clojure1.5. It is the author of the clojure program who decides by specifying in the project.clj file.
What I am saying is, I really prefer what seems to be the idomatic way of running clojure programs. This is totally possible with any programming language, but other jvm languages seem want to emulate the /usr/bin/runtime strategy. For instance the idomatic way to run a groovy script is to point /usr/bin/groovy --> ~/groovy-2.0/bin/groovy
That is exactly what the other JVM languages do. You download your version, of the language compiler and runtime, as libraries with a build tool. Then the build tool uses that compiler library to build your code. Saying that the idiomatic way of running groovy code is 'groovy myscript.groovy' is no more true than saying that the idiomatic way of running clojure code is 'clojure myscript.clj'
> The reason that you won’t find yourself running `clj` often is that the REPL built into bare Clojure is pretty much garbage....
This is what rlwrap is for. Call `rlwrap clj` instead of `clj`, and you get all that and more (C-r, for reverse incremental search, etc). Works with every other REPL that doesn't bother to re-implement read-line.
Using a raw repl at all is painful compared to just selectively evaluating expressions from a buffer (say, in Emacs, VimClojure, or the Eclipse and IntelliJ plugins).
I must second this. You can get used to it, and I did. For a while, I used Vim or ST2 + a terminal window with lein repl.
As of a week or so ago, I started using Emacs with Clojure & nrepl. Aside from the occasional teething problems (still not used to the Emacs paradigm), it's amazing. Merely having the REPL in a text-editor-like buffer is a big win, and there's a bunch more that I'm still incorporating into my workflow.
I agree! Anyone who ends up using Clojure more than a little bit will figure out how to use them, I'm sure.
But rlwrap is still a very useful tool because it works with every REPL. It will always be there, for those first sessions when you start learning a new language, or when you just need to answer some question about a language you rarely use, or when you write your own interpreter and don't want to also write read-line or an Emacs inferior-foo-mode.
I really wish I could remember why I didn't experience nearly as much pain starting out as the author, but I'm glad that he took the trouble to put this together.
Off topic perhaps, but is Rich Hickey's wisdom only summarized in talks, or has he written some of this down? I see a number of glowing reviews of videos like this. While I don't want to miss out, I would personally much rather consume this info in writing.
The one I did bite the bullet on and watch in full was his talk on “hammock-driven development”. I liked it, but couldn't help feeling it would have made a very nice blog post that I could've read in 5 to 10 minutes as opposed to watching a 30 minute video.
While 'Joy of Clojure'[1] can in no way be considered "the way Rich thinks", we have tried very hard to capture the Clojure philosophy as we understand it. This is based on personal interactions with Rich, his talks, the Clojure and Clojure implementations, Datomic, IRC chats and experience using the language every day.
I really suggest biting the bullet on "are we there yet" - it changed the way I think about state and identity (in that it got me to start thinking about them at all). I haven't found anything by him in written form aside from interviews, though, but I'm still really new here.
I can't speak to text, but you don't necessarily have to watch them. InfoQ offers MP3 downloads of talks, so you could listen to them on your commute, on a walk/bike ride/jog, etc. You'll still get 80% - 95% of the value.
I second fogus' comment about the Joy of Clojure, as well. I started with Simple Made Easy and the Value of Values before I even jumped into Clojure, and the Joy of Clojure dovetails quite nicely with all of the above.
That talk's definitely a good one. I particularly like how he frames it as a discussion about the difference between value-oriented programming (good) and place-oriented programming (what you're used to, bad). Giving the two paradigms those names really helps clarify how you think about the distinctions between the two.
I've always wished, though, that all "getting started" guides would just provide a chef recipe or machine image with everything ready to go. Getting to know a language shouldn't require jumping through an hour of hoops and documentation to get it set up.
(Of course, the guide here is broader than simply getting your system set up.)
Thanks to Leiningen[1], getting started with Clojure is super simple.
It doesn't get much easier than pulling down the master `lein` script (or `lein.bat` for Windows) with wget/curl and setting it up on your PATH as an executable. This is similar to rvm[2], nvm[3], perlbrew[4], et al.
You'll need to have Java installed before proceeding to the next step.
Once you've done that, you can run `lein repl` in your shell -- Leiningen will bootstrap itself when it's run for the first time, and when it's done you'll be presented with a Clojure REPL. Now you're ready to start exploring and learning:
Also, please join the friendly community in #clojure on irc.freenode.net[5]. You'll find folks in there nearly 24/7 who are willing to answer questions you may have as you learn your way around. The discussion group[6] is also a great resource.
I wanted to get Clojure on my secondary machine to do a little light fiddling, but as it turns out, Windows doesn't include wget or curl, and lein.bat requires those. So I have to download something that requires me to download something so I can download something that will let me install the thing I wanted in the first place. I think it could be a bit easier.
which makes me wonder if there is a simple java package to do that - probably not much to write a simple curl / wget for java so that on any machine with a JVM you can just lein your way to clojure...
I am using Windows more these days, because of work. I will start documenting what I have done to make Clojure and leiningen work properly, and see what can be contributed.
Which is fair. I don't use Windows a lot myself — this is basically the "League of Legends and Sims 3 machine." I was just pointing it out because lein.bat was mentioned, and I found it kind of surprising given how easy Leiningen is on other platforms.
Fair point, mea culpa :) I'll carve out some time this weekend, figure out how to make this advice generic across platforms, and figure out how to contribute it to dev.clojure.org.
I am a mediocre-at-best Java developer, but somewhat better at writing. I'd like to learn Clojure and contribute to the community while doing so. Is the Clojure Doc project the best opportunity for someone like me?
At first the Clojure environment is confusing: why do I need Leiningen? How do I use libraries in my project? This article is a good place to start for beginners, as it explains all that.
I started learning Clojure because it seemed to be the logical next step for me. In the few years that I've been programming full-time, I've noticed some patterns: in general, imperative code with lots of side effects in it is difficult to reason about and hard to test, and pure functions are easy to reason about and trivial to test. The same rule seems to hold for code that uses mutability vs code that deals only with immutable things.
Over the past couple of years, I've learned Common Lisp by working through Conrad Barski's Land of Lisp[0] and dabbled in Haskell via Learn You A Haskell[1]. I had a great time learning both, but I found that Common Lisp had a decent number of warts (e.g. four different kinds of equality) that seemed to be primarily due to backwards-compatability concerns, and I had a really hard time getting up and running when trying to write a simple webapp in Haskell. In addition, I've gotten spoiled by how batteries-included Python (which I use at my day job) is; the library scene for both of those languages seemed lacking in comparison.
What I like about Clojure is that it gives me fast immutable data structures, has a really strong emphasis on functional programming, and has access to a really huge amount of useful libraries.
So - I've mainly been learning Clojure as a nice treat for myself; the amount of jobs that exist that employ programmers to code specifically in Clojure didn't even really occur to me as something worth thinking about. It's just really a lot of fun to program in. Also, with any luck, I'll be able to transfer any lessons I learn from Clojure to my daily work in Python.
(Haskell still has a very special place in my heart [I do frequently find myself wishing I had types], I'm not trying to dis Common Lisp nor Haskell, I'm just trying to honestly answer the question of why I thought it was worth learning Clojure).
I realize this is quite off the main topic, but I thought it was interesting and worth passing on.
If you really think that "four different kinds of equality" in Common Lisp is a wart, then I recommend that you read "The Best of Intentions" (http://www.nhplace.com/kent/PS/EQUAL.html) by Kent Pitman. The article explains why that situation is quite intentional, and why it is very rational, and why it is in fact ill-advised to expect a single meaning for "equal" ... or, in fact, other "obvious" concepts like "copy" ... to be sufficient.
That article was one of the many over the years that helped me refine the way I think about programming and programming languages.
What do your superiors think about implementing new, small projects in Clojure?
When you say "has a huge amount of useful libraries" but then say that Python is "batteries included", which libraries in Clojure are particularly useful? Which ones did you wish it had?
2) I used those two phrases interchangeably - I consider both Clojure and Python as "batteries-included" languages. Case in point - before I was aware that Clojure Toolbox existed, I was able to google "clojure http request" and find several libraries that let me perform HTTP requests programmatically that I could include in my project.clj and start using right away. My memory's a little fuzzy, so apologies if this is completely wrong, but I don't recall having as easy a time doing that in e.g. Common Lisp or Haskell.
As far as which libraries in Clojure are particularly useful - Ring and Compojure are fantastic, and core.logic[0] is extremely interesting; I'll write a blog post showcasing core.logic (and using it for my first time ever) at some point. Midje is great for writing unit tests. I've only been using Clojure for a few months, so I can't point to too many others that have really been extremely useful for me, but I definitely recommend checking out the Clojure Toolbox[1] for a more thorough list of the main contenders.
To me, this is the smartest part of using Clojure in your projects. If you're a company with an enormous Java stack, it's trivial to add things like Clojure or Scala and use them as scripting languages. Or break out a library and rewrite it using one of the two, if that problem would be better solved more functionally.
Basically it makes it easy to convert projects without tearing down your infrastructure, ie, easy to convince your boss.
This post is specially relevant for me, since last weekend I've decided to take a quick look at Clojure, as one of my personal goals this year is to get acquainted with a Lisp dialect.
From my _very_ short experience (I've started coding a simple game), here are my two cents:
- If your application is heavily dependent on state, which changes continuously and must be maintained during most of the execution time - like a game - it may not be a good fit. You'll waste a lot of working around the fact that each modification results on new objects.
- If your application comprises mainly of short requests that may create some state that will most certainly be discarded shortly after - like a web application - then I think it's a good fit and you'll probably enjoy it better.
Once again, I've just got started with it, so take this with a grain of salt :)
I'd like to contrast this: if your application is heavily dependent on state, especially state which is shared between threads, Clojure offers a concise, safe, and uniform way to understand and organize state transformations--at the cost of performance. Where fast mutability is required, it's easy to drop down to explicit locks, atomics, java.util.concurrent collections, et al.
I find the majority of my time in writing stateful programs goes towards reasoning about safety, and having access to STM lets me write correct code with less thinking. Then I focus on optimizing the parts where performance is critical.
At ILC 2009, Guy Steele asked Rich Hickey how Clojure's STM interacted with I/O. To which, Rich replied that it doesn't. No further discussion continued on the subject.
I have found that this rarely enters discussions regarding Clojure, although the STM is frequently lauded.
GHC's STM also does not work with the IOMonad, which is clear because of the types, and is articulated in books such as such as Real World Haskell.
The critical thing, as you observed, is to separate IO from retryable STM transactions with a barrier; e.g. by receiving data, doing an idempotent computation inside dosync or swap!, and then emitting results. Haskell has an advantage in that this separation is provable by the type system, whereas in Clojure you need to remember.
A contrived example:
(let [pizza (get-from-fridge)
meal (dosync
(alter eaten-foods conj pizza)
(deref eaten-foods))]
(tell-friend "So far I ate" meal))
where get-from-fridge and tell-friend are IO operations, and our list of eaten foods is mutated by pure functions.
In practice I don't find this particularly limiting: dosync and swap! are almost always short operations for performance reasons anyway. Then you return a consistent snapshot of the updated state from dosync--where multiple pieces of state are involved, you can use vectors or maps along with destructuring bind. Sometimes it's a tad unwieldy, but typically much shorter than the equivalent mutex dance.
There are other aspects of Clojure's concurrency libraries, like agents, futures, and promises, which are useful in IO. Specifically, agents give you asynchronous serializability, futures give you asynchronous concurrency, and promises allow for synchronous handoff of delayed values. Those are quite useful when working with IO, though for heavy lifting you may be better off using explicit queues and worker pools from java.util.concurrent.
Sometimes I think of Clojure (as an imperative language) as the dual of Haskell's lazy evaluation model. Clojure uses futures, promises, and lazy sequences to provide explicit laziness, where Haskell uses the IO monad to provide explicit ordering. Both have an STM for serializable, atomic mutability between threads.
That's odd, that seems a little inaccurate to me. Clojure's agents are useful for encapsulating I/O-related resources, and are integrated with the STM system. Per http://clojure.org/agents -
Agents are integrated with the STM - any dispatches made in a transaction
are held until it commits, and are discarded if it is retried or aborted.
Refs and atoms shouldn't have side effects, but agents are great for performing side effects. From page 214 of Clojure Programming:
Unlike refs and atoms, it is perfectly safe to use agents to coordinate
I/O and perform other blocking operations. This makes them a vital
piece of any complete application that use refs and Clojure’s STM
to maintain program state over time. Further, thanks to their semantics,
agents are often an ideal construct for simplifying asynchronous
processing involving I/O even if refs are not involved at all.
Further:
Agents are integrated into Clojure’s STM implementation such that
actions dispatched using send and send-off from within the scope
of a transaction will be held in reserve until that transaction
is successfully committed. This means that, even if a transaction
retries 100 times, a sent action is only dispatched once, and that
all of the actions sent during the course of a transaction’s
runtime will be queued at once after the transaction commits.
For games, Chris Granger and his team have coded up a prototype game in Clojurescript using the Entity-Component-System architecture, which seems to be a good fit for functional languages. It might be worth checking out: http://www.chris-granger.com/2012/12/11/anatomy-of-a-knockou...
Actually, in my experience the practises in the high-end AAA game industry are now much closer to FP than the rest of the industry. The current-gen consoles have lots of really weak threads, and to get any decent performance you have to use a lot of them. So, modern games do things like double-buffer the entire world state to allow efficient multithreading.
Learning a powerful, less main stream language like Clojure can also signal to smart, innovative software companies you might be the kind of person they should hire.
I wish someone would do a Learn Clojure the Hard Way. The comments in this thread is a great documentation of the unfounded fears of the language.
I also want to point out to those who are using Windows: Yeah, you could, but this is not a good idea. Leiningen 2 is not available for Windows, but you can still get quite a bit done. At some point, you just have to bite the bullet and install a VM with Linux to really dive into it.
Leiningen 2 is absolutely available on windows. And clojure on windows is the same as clojure on any other platform. That's the beauty of running on the JVM.
Light Table has a windows client; Eclipse with the counterclockwise plugin (a leiningen/clojure plugin) runs great on windows; running from the command prompt works great on windows.
I agree though, that a "Learn Clojure The Hard Way" a la Shaw would be nice.
Really? The only thing I get when I attempt to install Lein2 on Windows is "This is not available on Windows." Running Windows 7 Home.
I'm not a huge fan of using a bunch of IDEs and just use Emacs. After a year of fighting with Windows, I got fed up with it and installed Linux with a VM and now everything works like a dream.
EDIT TO ADD: I would love to do a project like Learn Clojure the Hard Way, but I'm simply not confident in my abilities to do it correctly. I've written some pretty significant programs in Clojure (see my profile), but I wouldn't be able to solve but a few Project Eulers with it. I'm simply too new at programming in general.
I'm a Mac person myself, but use windows for work and have leiningen and clojure running fine.
I just used the batch file from the leiningen github to get up and running on windows.
Someone else brought up the point that lein needs wget or curl, and that isn't something that is installed by default on windows. I happened to already have them, so I never thought much about it.
GNU has a version of wget and maybe curl too for win32. And there is always cygwin if you like.
I'm pretty much a novice when it comes to software in general, but I dip my toes in a lot of different languages. I don't think that would be a problem for LCtHW though... I mean, it could be a collaborative effort as a github page or wherever.
Get the framework in place, start with the basics, let the experts fill in the advanced stuff.
"When I was going through all this myself a few months back, there was a weird period of a good few weeks when I had basically no mental map of the Clojure ecosystem and had no idea how to assemble one."
One of the things you can do when learning something new is to hop onto IRC and join a channel related to the topic. I almost always have got a good overview of things just by asking around what I am supposed to know.
I'm interested in learning LISP.
How good a choice is learning Clojure as a way of achieving this?
I've read a page[1] listing differences between Clojure and other LISPs, but I'm not sure that I fully understand the implications of these differences.
Clojure's a great lisp. I recommend it highly. I haven't spent much time with Scheme, but I can definitely say that I greatly prefer Clojure to Common Lisp.
this video by Chas Emerick (co-author of clojure programming) also gives a good introduction to start with clojure, especially for people who uses eclipse.
The same thing could be done in Python (with requests) and Ruby (with whatever-it-is) with more clarity, less confusion, and much less consumption of resources.)
(:headers resp)
This construction is confusing - it breaks environmental model (scoping) and general evaluation rule of Lisps - is :headers a global symbol? a part of foo namespace? Is it macros?
(resp :headers)
On the other hand, this form is perfectly consistent - I'm sending to some closure which is bound in a global or other environment a constant message.
The assumption that the reader function implicitly transforms first form to second is of no good, because it is not obvious and breaks intuition about environments and violates principle of less astonishment.
That thing (:headers resp) returned - what language is it?)
>This construction is confusing - it breaks environmental model (scoping) and general evaluation rule - is :headers a global symbol? a part of foo namespace? Is it macros?
It follows Clojure's evaluation rules just fine: it's an object that implements the IFn interface.
> On the other hand, this form is perfectly consistent - I'm sending to some closure which is bound in a global or other environment a constant message.
resp isn't a closure, it's a map, which is also an object that implements IFn.
The keyword syntax is transformed into a keyword instance by the reader, and keyword instances implement IFn as objects on the JVM, hence can be used as functions under clojure's evaluation rules.
As I understand it, the roles which things like lists and functions play in a traditional lisp are replaced in Clojure by abstract datatypes corresponding to Java interfaces. Which on one hand is kinda neat because the core lisp datatypes aren't tied to specific concrete implementations and other datatypes (including user-defined ones) can participate in the same abstractions.
On the other hand it means the semantics become quite tied up in underlying JVM-related details and don't seem as clean/elegant as (say) Scheme.
On the other hand it means the semantics
become quite tied up in underlying JVM-related
details and don't seem as clean/elegant as (say)
Scheme.
That's not very true. Instead, Clojure is defined in terms of specific abstractions. Whether those take the form of interfaces or protocols is irrelevant because it's the abstractions that count. If it were tied strictly to JVM-related details then ClojureScript would have been much harder to implement than it was.
You have to use the java interop facilities if you want your own types to implement these abstractions though right?
I recall some debate about changing this so you can implement them using the native abstraction facilities in clojure (protocols), at which point I'd probably withdraw my point.
But yeah elegance is subjective. I use Clojure and broadly like it, JVM interop is really useful, but the lack of a crisp separation between clojure semantics and JVM semantics does still irk the purist in me a bit.
I guess I'd see Clojure and ClojureScript not as one language on two host platforms, but as one JVM language and another similar but not really source-compatible language on another platform which is influenced by it. Part of the philosophy seems to be to make pragmatic decisions which blur the boundary with the host platform, rather than try to abstract over the differences in APIs and runtime semantics.
Not quite, I'm talking about replacing the various important java interfaces in clojure.lang (IFn, ISeq, IPersistentMap etc) with protocols, so you can implement them yourself without using any Java-specific language features.
Dunno how feasible this is, but if a language is going to define its own abstraction features (here, protocols) on top of the underlying platform, it would seem cleaner to eat ones own dogfood in using these abstraction facilities for the core abstractions which the language and its core library are based on.
It is also a function though, and can be used in the function position of a function application just like any other function.
Keywords and all their functionality are defined as a primitive in Clojure, i.e. in the Java source code for the language.
It's typically one of the first things people learn when they pick up Clojure, and is used as an idiomatic way to access maps whose keys are keywords. I would argue that is is not confusing and that it is totally consistent - all you were missing is one fact: keywords are functions.
From the Lips's perspective it is a contradiction. Something is either a function or a constant.
The logic is that this object could be called as a function and at the same time always evaluated to itself?
That means whenever you call it you always getting it back - this is behavior of a constant. But if you could call it with an argument, you will get back some value, different from whatever it is?
As long as maps are immutable, it will behave as a function - return the same value for the same argument.
OK, but, please, don't tell me that this isn't confusing.)
> That means whenever you call it you always getting it back - this is behavior of a constant.
No! You're confusing functions-as-callable-things and functions-as-values. The phrase "a constant" does not generally imply anything about a thing's behavior when called. It just means something whose value will never change. A self-evaluating constant is a constant that circularly evaluates to itself — nothing else can have that value without referring to the constant. But neither of these things have to do with calling anything; they're just about taking values.
A constant can certainly refer to a function that returns something other than that constant. For example, in Ruby: `Example = lambda { 1 }`. If you just evaluate "Example", you will get a Proc value, but if you call Example, you will get the Fixnum 1.
In most languages that have them, you cannot call a self-evaluating constant. It won't return itself — it's just not a callable thing. In Clojure, keywords are self-evaluating constants that have the behavior of looking themselves up as a key in the argument when called. They serve the purpose of self-evaluating constants exactly the same as in other languages, but they also have the handy property of doing map lookups.
@baar: FYI, you appear to be hellbanned (your comments are being automatically killed as soon as you post them). New accounts are particularly susceptible to this, as it seems like the auto-ban algorithm kicks in when you have low karma and get too many downvotes in a short time, or something like that. You should be OK if you make a new account and avoid making very harsh comments so you don't draw downvotes.