Clojure++ (notes from Rich Hickey talk)
combinate.us
combinate.us
(def (fib n :: <long>) :: <long>
(if (<= n 1) 1
(+ (fib (- n 1)) (fib (- n 2))
Almost identical speed results to Rich's "improved" version.The did it for a dacade and rich does it for a couple months and you bash him? We arn't the kawa guys faster after a decade.
Clojure is faster in other stoff like interop witch is really importend on the JVM. Can Kawa write down-to-java speed types?
Kawa guy. Kawa was written by a single person, Per Bother, in his spare time. Clojure has a massively larger mindshare and collection of coders behind it. Ask yourself: why has Clojure been so slow for so long?
> Clojure is faster in other stoff like interop witch is really importend on the JVM.
Actually in my experience this is where Clojure is very slow indeed. If Clojure has to convert everything to Refs, it gets extremely slow (in our tests on my simulation system, up to 1000x slower than Kawa. I am not making up that number.).
> Can Kawa write down-to-java speed types?
Absolutely.
The ^long thing is pretty cool bettr then : <long> or something. Its nice that it is just metadata.
See also, ADD 1 TO COBOL GIVING COBOL.
which is probably really good marketing. (About e.g. "succ ml", I'm not sure.)
Rich Hickey loves to rail against nonsensical constructs/concepts like @date.day = 3, and I'm guessing he is very against the (++) method, as well. (How can you tell one number to become another number?)
(I was thinking of tattoos, PS.)
With TCO, you can use a set of mutually-recursive functions - you can set up a FSM via tail calls, use CPS for backtracking (and many other things), a re-entrant virtual machine where each opcode is a tail call (rather than a giant switch/case or lots of gotos), etc. Being able to use function calls like "gotos with arguments" (but with local scopes, etc.) can make some constructs much easier to read, reason about, etc.
I'm not that familiar with the implementation of the JVM, but AFAICT it's due to difficulties setting up tail calls efficiently in JVM bytecode.
As soon as the JVM supports it Clojure will support it. For me recur and trampoline are quite ok. I would want to miss on clojure because of TCO but I don't know what would be possible with TCO. I hope I can learn that in one of the books I have here :)
And yeah, I thought of mentioning trampolines, didn't know that it already had a readymade one. Sometimes they add too much overhead, but often it's still a good trade-off.
If I could do it again, I'd go with (inc clojure), as below.
Oh no! Clojure is choosing the route of premature opt. What a terrible shame.
Bignums "contaminate" surrounding operations. Adding a long and a bignum yields a bignum. Seeding an equation with a single bignum (42N is a bignum representation of 42) will prevent overflow.
No one has come forward with a single real-world scenario where they're using bignums in Clojure. Choosing a default that is only theoretically useful rather than a 10x performance improvement seems a bit silly.
In any situation where the compiler cannot be sure you're using primitives everywhere, it will emit non-overflowing bytecode.
By my measure, there's nothing premature about this optimization. In Rich Hickey's words, Clojure is a replacement for Java, not Ruby. Giving up Java-like performance makes the language quantitatively less useful.
EDIT: If peregrine's comment is right, then we're arguing about something that isn't happening. I hope so.
That is very clearly the opposite of what I wrote.
More importantly with these changes it's now possible to reimplement Clojure's core datastructures in Clojure without sacrificing performance.
The majority of people who care about BigInts are solving Project Euler problems, not writing Clojure libraries or deploying apps into production.
I'm thirsty for counterexamples.