Clojure vs Java, pt. 1
tech.puredanger.com
tech.puredanger.com
I would love to have this in Ruby, so that classes could be extended but not in surprising ways.
Exactly. Funny thing. Better OOP in a functional language than in a OOP-language.
But i don't think it's hard to understand. I've seen a lot of good explanations in presentations and articles. Also the concept is really easy.
[1] http://stackoverflow.com/questions/105834/does-the-jvm-preve...
Please bear with me as I'm not familiar with Lisp family languages. I'm interested in ML languages. There is a project to port OCaml to JVM, but I don't see any sign of progress, so I thought it may be something on JVM to hold them back.
OCaml on the JVM would have the same problems, if not worse. Eliminating tail recursion is essential in the ML family, and doing that while sanely supporting Java interop seems to be difficult.
I don't really keep up with it much, but I remember proposals to give some bytecode operations that would help here in the next Java version. Not sure if any of them made it past that stage.
The JVM security model allows a function to goto anywhere inside the current function, but does not allow a goto to outside the current function.
This means that JVM based languages can do tail call optimizations in self-recursive functions, but can't TCO in mutually recursive functions.
With Clojure, Rich Hickey thought there was some accidental complexity here, so he added the recur special form. Recur guarantees the call is in the tail position, and throws an exception if it isnt. Recur can go to the top of the function, or an enclosing loop block inside the function.
To do mutual recursion in Clojure, you use a trampoline. That looks like
(declare even? odd?)
(defn even? [x]
(if (= x 0)
true
#(odd? (dec x)))
(defn odd? [x]
(if (= x 1)
true
#(even? (dec x)))
(trampoline even? 100)
What we're doing here is defining two mutually recursive functions, but instead of calling the other directly, we return a function of no arguments that calls the other function. Then call trampoline, passing the function and any arguments. Not the most elegant solution, but it works.If you're dispatching based on something other than just type (some information that would allow you to choose one of multiple implementations) than you should probably either a) put that logic inside the protocol implementation for that type or b) use multimethods which let you use an arbitrary dispatch function that can take both type and other information into account. If you choose a), you could actually layer another protocol or other dispatch mechanism under the initial call if you need to.
For instance, it would be perfectly feasible to use a multimethod that dispatches on both type and output format. Or a protocol that dispatches on type, then dispatches a different function on format.