Hacker News new | comments | show | ask | jobs | submit login
How practical is Clojure? (johnfn.github.com)
85 points by johnfn on Sept 6, 2011 | hide | past | web | favorite | 20 comments

If the author is reading, I assume you tried the clojure.stacktrace module?

Error messages can definitely be tricky to figure out. A stacktrace, however, will often give enough information. Simply start looking down the stack for the first function that is part of your code base. The function may or may not have a line number. This depends on if you've loaded the source as a file, or sent an individual function to the repl on its own. In the latter case the line number information is simply not available to the language.

Using the stack traces solves 90% of issues I encounter. If I need line numbers, I restart the REPL and make sure that information is present. It's rare indeed that a stacktrace doesn't help at all, although it happens. I also use print debugging frequently. The REPL makes this technique a lot more reasonable than it is in say, C.

What would you suggest to improve the debugging/error situation?


If I had to choose a single biggest weakness for clojure adoption, I would say the lack of good documentation and also standardized process that is often so important when working in larger teams. The core documentation is good for experience developers, but lacks examples that many others find useful. The books clojure books are good, and clojuredocs.org is a great idea that has yet to get enough traction to become the standard go to place for documentation.

That said, it is still a young language and the community is working hard at addressing these issues.

I am familiar with stack traces, and it's certainly true that with enough experience you can solve a majority of errors just by analyzing the stack trace. But I seemed to run into strange edge cases where the stack trace never mentioned my source file, or would only say line 0. (You mentioned that that could be because I sent the function to the REPL, which is something I never considered! I will definitely have to go back and check, but I think that there were times when that was not the case.)

> What would you suggest to improve the debugging/error situation?

The easiest possible improvement, and something I might write soon, is a simple stack trace parser that would extract only the relevant information. If Clojure errors said "Probable error at this line" first, and then gave me the stack trace after, that would be a lot more user friendly, especially for beginners. And it seems pretty straightforward to parse out lines that have the current file name in them, etc.

If you try 1.3, the clojure.repl namespace contains some niceties:


This is something I'm very interested in addressing. What documentation is missing? What is it that you feel is needed for people to get started and stay hooked?

For example, is www.webnoir.org filling this need in the web space? Would a better clojure.org with Noir like examples fill the gap?

Here's an example of something that I've run across in my time dabbling with Clojure: How do I define my own collection class that can be used with all the standard functions? It seems like it should he straightforward, but the existing documentation seems to almost deliberately talk around it. Along the same vein, how to I define a type that works like a function, like keywords and sets do?

And then there are simple questions like how to make a concurrent application. The docs go on at length about how Clojure helps concurrent applications, but not a whole lot about what is a reasonable way to make one in Clojure. You're just told how great it is for the task and then kind of thrown in with a list of functions and told to get to it.

Your issues touch the Java side of Clojure which admittedly is not documented very well if at all. Currently you need to implement multiple Java interfaces to completely customise behaviour (which is why Clojure tries to give you enough tools so you don't need to do it). I suspect that once some of the Java interfaces get replaced with Clojure protocols, things will get easier.

However, these are issues that rarely come up in idiomatic Clojure. Most of the time you don't need your own collection classes, or new types that work like functions. It is possible, but since it's a rare need, I'm not surprised the documentation on how to do it is indirect at best... deftype is probably the best tool if you need something low-level like that, or defrecord if you just want something that works like a map.

Your 'simple' question isn't exactly simple either. The famous ants simulation is a fair example of a concurrent application, but often the design depends on the sort of concurrency you need, and the simple question suddenly becomes much more difficult. More examples wouldn't hurt, of course.

I agree that the things I named aren't tasks of huge importance, and I hope it doesn't seem like nit-picking, but they were examples of the sort of thing I like to do when I'm first looking at a language. I like to play around with the features the language touts, to try to get a good feel for how it "thinks". The other option is just to start out writing unidiomatic nonsense that doesn't use any unique features of the language, and I feel like I'm teaching myself bad habits when I do that.

Anyway, my point is, this is pretty much the state of the Clojure documentation right now:

On Clojure.org:

- List of features

- Alphabetical list of functions stretching as far as the eye can see

On ClojureDocs.org:

- List of functions by namespace

- Long list of functions by "category"

- A cheatsheet consisting of the long list of functions by category with descriptions removed

ClojureDocs is much better, but it still isn't enough to even implement a simple facsimile of hash-set or figure out how to start multiple threads in order to take advantage of all those swanky concurrency features. (The concurrency example is actually something practical I wanted to do. I have a slightly quirky bin-packing algorithm that I wanted to parallelize and I felt stumped staring at the list of functions. Finally I found a Stack Overflow post that said to just use Java's Thread.run with a Clojure function.)

Yeah, currently Clojure sort of assumes that you know enough to fall back to the Java class library if you can't find something in clojure.core, threading being a good example.

The documentation is mostly terse, but there is http://java.ociweb.com/mark/clojure/article.html which is more tutorial-like; though it's probably getting a bit old by now.

Idiomatic way to do it is usually to call "future".

One of the easiest way to understand some of the mysteries of Clojure is to read the source, a large amount of Clojure is written in Clojure and the source for most functions is just one click away.

I agree though, lots more examples would be nice!

Let me break this down into parts. I'll address the web space specifically. For reference, I've had over a year of clojure development experience now. Some of these statements are from my own perspective, others from complete newcomers to clojure that I've talked to or worked with:

1) Most of the time I resort to reading the actual source.

2) There are many libraries which have native clojure documentation on each function, but lack a website summarizing it.

3) Trying to figure out how all the various web components fit together is very time consuming.

3.1) How do ring sessions handle security? (they default to a memory store, but you need to dig to find this, I don't know if the cookie store uses encyrption)

3.2) ClojureQL is still in heavy development, but the documentation is lacking answers to many frequently asked questions. EG:

3.3) How does one execute a series of statements in a transaction?

3.4) How does one retrieve the id of the record just inserted?

There are answers. For the first, you can use clojure.java.jdbc, or clojure.contrib.sql, given some constraints. For the second, you can't, but the latest dev snapshot can.

3.5) How do you execute arbitrary SQL? (you can in batch with jdbc, but not all statements work in batch)

3.6) session expiry, a critical feature. But you need to dig to find hozumi/session-expiry. Also, it doesn't work with sandbar's stateful sessions in my experience. All not documented.

3.7) security restrictions are another huge problem for clojure web frameworks. Sandbar's are ok, but still limited and not particularly performant. I'll try to get some code released soon on this front.

3.8) Understanding how ring and it's requests work is a challenge. There should probably be a small book chapter explaining the architecture of this. I understand it, but it took a lot of reading on mailing lists and ultimately the source code to figure it out.

4) Beyond documentation. Clojure web frameworks are based on composing many small components. This is great and has many strengths beyond those of other frameworks. However, a lot of users are looking for a turnkey "do this, do that" solution. They want to know the best standard practice. This is process, something that gives strengths to frameworks like Ruby on Rails.

While I would not suggest abandoning the composability of clojure web frameworks, having a standardized large scale framework with standardized process would go a long way to getting more widespread adoption.

For example, a framework with recommendations for large scale code organisation like model view controller, or similar functional equivalents, along with recommendations for standardized modules and coding practices.

Webnoir is still too much of a micro framework to handle these needs. We don't need to abandon flexibility and composability. However, there needs to be a manual of best practices along with code that makes it easy to use for common web app development, all details included.

Above all, a central resource tying all these points together is what is needed. I too want to help with this.

> Leiningen (the Clojure build tool) is written in the JVM, and on my machine it always takes 5 seconds just to start.

The lein help command does more than simply print a string, it searches for plugins available on your system. To measure the startup time of lein perhaps you should do:

  % time lein version                                                           ~
  Leiningen 1.6.1 on Java 1.6.0_26 Java HotSpot(TM) 64-Bit Server VM
  lein version  0.75s user 0.05s system 130% cpu 0.612 total
Less than a second, not bad.

> time lein shows about 10 seconds to display all the output, and then it hangs for about a minute more before the process completes.

So there's a problem on your system. Most people don't have that problem. Check your plugins.

I also have that problem time leon lein 8.70s user 0.45s system 159% cpu 5.739 total

Saying "oh fix your whatever" is just passing the buck. This is a frequent enough problem to be a major issue. If there are more than a few of these issues people will simply move elsewhere. Rightfully so too.

ClojureScript won't have the startup time of the JVM and is probably better suited for command line scripting.

Why don't they integrate something like nailgun? Run a JVM in the background and redirect command line execution.


People have done that with Clojure, see cake and jark. There are tradeoffs.


That is incorrect. It needs the JVM to compile, but once compiled it's pure JavaScript... so the startup time would only be node's.

Good point. Thanks!

Well, Clojure has hot-swapping code for source Lisp files, but you can't load compiled libraries (Java, Clojure, Scala, whatever) into the running JVM, as there's no way to dynamically add JARs. This is quite a limit, especially in production scenarios.

How about evil-mode? I heard it's newer than vimpulse.

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