Sign up ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

The Java implementors seem slow to adopt language improvements, for example compare C# with full closures, expression trees, LINQ etc.. to Java, and even the push back of some stuff to Java 8 will still leave it behind the current implementation of C#.

However since I dont intend to use either Java or C# that particular language war isnt of interest too much, im more concerned with the JVM vs CLR.

Is this lagging-behind also applicable to the JVM?

Will Scala, Clojure etc.. will they be able to continue to innovate or score optimal performance in the face of slowly progressing underlying VM such as JVM? Is Clojure/Scala restrained at present by JVM limitations?


migration rejected from Jun 27 '14 at 21:26

This question came from our site for professional and enthusiast programmers. Votes, comments, and answers are locked due to the question being closed here, but it may be eligible for editing and reopening on the site where it originated.

closed as primarily opinion-based by gnat, Bart van Ingen Schenau, MichaelT, Dan Pichelman, user61852 Jun 27 '14 at 21:26

Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise.If this question can be reworded to fit the rules in the help center, please edit the question.

it's worth noting also that Clojure targets the JVM, the CLR, and JavaScript (via google Closure). – Arthur Ulfeldt Jul 29 '11 at 18:15

2 Answers 2

I am somewhat experienced with Clojure as a new JVM language and can confidently state that the language isn't particularly limited by the JVM. In particular it's worth noting:

  • Closures are fully possible and very efficient - this isn't a JVM limitation, more a limitation on Java syntax
  • Macro metaprogramming is great and works well on the JVM (far superior to anything in non-Lisp languages)
  • Dynamic typing is fully possible and works well
  • Lazy evaluation works excellently, and is actually often the preferred/idiomatic solution in Clojure rather than using recursion (that might need TCO).
  • Modern JITs actually use Escape Analysis to avoid heap allocation where it is unnecessary (e.g. an object used solely to contain a couple of return values from a function would actually get allocated on the stack)

There are couple of things that would be nice to have in the JVM for Clojure (I understand these will probably make it into future versions):

  • Proper tail call optimisation - Clojure allows explicit tail recursion with recur and you can use trampolines if you want non-stack-consuming co-recursion, but proper TCO would still be a nice optimisation.
  • Value types - again would be nice to have, there are a few cases where this would be very convenient and avoid some heap allocation.

On the other hand there are also advantages to the JVM:

  • Cross platform

  • In my experience, the GC and JIT compilation have been better on the JVM than on any other platform

  • A very comprehensive library / open source ecosystem

  • The JVM / JDK itself is available as open source (OpenJDK)

Overall the JVM has proven to be a very good platform for FP via Scala, Clojure and various other languages. I'll personally be sticking with the JVM because Clojure is amazing and cross-platform portability is important for my applications. I've certainly not seen any compelling reason to move to any other platform for server side applications.

I would also say that I like that Clojure forces you to write "(recur ...)" to denote tail-call optimization. That way, the compiler catches it when you want to do a tail call but messed it up by not making it the last operation in the function. In Scheme, such programmer errors are left uncaught until you blow your stack depth limit at run-time. – SuperElectric Oct 10 '11 at 19:00
Yeah, I've found the Clojure (recur ...) construct quite helpful that way. It's proved to me that "full" TCO isn't actually much of a big deal - you can do everything you want to do pretty easily without it. – mikera Oct 12 '11 at 4:11
@SK-Logic - You seem to be trying to argue that TCO is what defines a functional language? That's just comical, it might be very useful sometimes but it's only a feature - this is like saying four-wheel drive is what defines a car :-) . Also I suggest checking your definition of tail call - you'll find that a tail call is defined as any call in tail position. Compiling this into a jump or a loop is an optimisation (TCO), which is the usual term for a change that reduces space and/or processing requirements but otherwise leaves the result of an algorithm unchanged. – mikera Sep 19 '12 at 9:52
Clojure supports the full lambda calculus including tail calls just fine without doing automatic TCO. Your own example (defn [g x] (g x)) works just fine in Clojure. You are mistaken if you think that TCO is required to support the lambda calculus (the lambda calculus doesn't actually say anything about implementation). All TCO means is that some constructs can execute with less stack space. This is nice to have but it's ultimately not a big deal - I have never found a situation where lack of TCO was a problem in the real world. Are you in research or academia by any chance? :-) – mikera Sep 19 '12 at 11:06
@SK-Logic - You make some interesting points and I was genuinely interested in your perspective. However you don't seem to be able to conduct a reasonable and polite discussion - it seems almost as if you have some sort of axe to grind. Also this is the wrong place for extended debate. Hence I see no point in continuing this discussion. Bye! – mikera Sep 19 '12 at 11:37

I have to add an example that I bumped into myself.

This isn't really a limitation, but rather a leaky abstraction, however the Scala language which is implemented on the JVM has been impacted by its underlying architecture.

The language differentiates between methods, that are defined using the def keyword, and functions, that are actually objects with an apply method.

You can read more about the effects of that in this question.

In short, this means that:

  • You can't have genericized lambda expressions
  • Sometimes you have to explicitly convert methods to function objects so they can be passed as arguments, with a really simple syntax though: f _