Clojure 1.3 First Impression (It's Fast)
learningclojure.com
learningclojure.com
Anyway, pretty fractal tree program in lisp!
The article also doesn't get into deftype/defrecord/protocols. In those cases you always get the fastest path of the platform. Again you can build things that have the same perf of the core data structures w/o resorting to ^:static or type decls.
So what exactly do you mean again by arbitrary code? Perhaps you meant numeric code - there ^:static and type decls help plenty. Perhaps you mean Java interop? Again sure.
Personally I think Clojure is really taking the dynamic, generic, and fast thing to a whole new level, w/o type-hinting of any kind.
EDIT: This isn't too say Clojure performance can't continue to improve. Scala's ability to use Java arrays of primitives in higher order operations is something I really, really want to see (and the the above is a big chunk of the work in that direction)
Clojure is awesome because it provides immutable persistent structures that are well onto the good side of "good enough", not because it's the fastest thing possible. Java itself is far from the fastest thing possible, and the speed of Java is itself a strict upper bound on Clojure's speed.
I think the history of production oriented PLs has revolved around balancing correctness/performance. And it's always a question of diminishing return (I've written enough C/C++/Objective-C++ to know this). Every sizeable application I've written in a lower level language eventually approaches some kind of wacky manual memory management scheme to preserve performance w/o sacrificing correctness. I think Clojure's solution is a step in the right direction.
But no, if I was writing a real-time system with extremely limited memory constraints I would not write in the Clojure. But I don't think that's what this thread is about.
Sometimes you just need something at Java's (or preferably Scala's) position on the power/performance spectrum.
That said, the way Clojure is improving, I think it will continue to asymptotically approach Java's speed anyway.
Clojure doesn't compile to Java, it compiles to JVM bytecode, and I think (although I don't know) that that's supposed to be very fast.
In this post:
http://www.learningclojure.com/2010/09/clojure-faster-than-m...
I compiled a (lookup into a map (potentially constructed at run time)) into a series of nested if statements, which then ran very fast indeed.
I shouldn't think I've achieved anything like the holy grail here, it all goes wrong at the end anyway, and I think that clojure 1.3 might actually have broken the optimization techniques I used.
But I think there's a case for saying that an immutable lisp on the JVM might one day be the fastest language in the world, because you can do those sorts of tricks in lisp in a way that you can't feasibly do in assembler, and the JVM does optimization dependent on run-time behaviour, as well as on static analysis.
I don't have the data. I'm not asserting this.
But I am asserting that Java speed is not a strict upper bound on JVM language speed, (unless every JVM bytecode program is also a Java program, which I can't imagine is the case!).
There are a couple of drawbacks, though:
1. It really only works for read-only data. Generating a new lookup-fn is a pretty expensive operation. I don't think I could use this for data that changed at all.
2. Compiled code uses permgen space and isn't garbage collected as easily. If you make extensive use of this technique, especially with large maps, it'd be really easy to blow your permgen space.
That said, in reality, JVM bytecode is tied pretty closely with Java. The bulk of a program: method calls, types, loops, etc all map pretty much 1:1 with what Java emits - there's not a whole lot of room for improvement. And if there were, it would probably be through MORE static typing and compile-time analysis, not less.
I expect that for any arbitrary Clojure program you give me, I can write a Java program that will execute as fast or faster. Of course, it might take me ten times as long to write and have ten times the amount of source code.
I think clojure is getting really close to a dynamic language that can get down to the speed of a static language if you need it.
So a general strategy is to write your code as you normally would - def'ing redef'ing fns at will. Then when it works - declare the critical paths ^:static, and adding primitive type hints ^long, ^double if the code is numeric.
Not sure if that's a better or worse approach overall. It probably depends on the structure of your program. One nice feature was that the same function could be static from some perspectives and not from others--- to functions in the same compilation block it was static, but functions from outside that block that called it treated it as non-static, and would immediately get the new version if, say, that whole block were recompiled. That let you make the core code optimized by sticking it in one big compilation block, while not changing the normal dynamic Lisp semantics of the block when viewed from the perspective of any outside function.
typhinting to avoid reflection can be done for all java objects. The autoboxing is only for numeric stuff.