Hi all, I'm super tired, so apologies if this has already been covered, but I think portability is the main issue. Java is very portable, whereas the CLR is focused on a single platform.
Also, most of the innovations in the Clojure space have been built on top of the JVM. Until Clojure reaches critical mass the really interesting developments are going to be created by the Clojure community, for the Clojure community, and the simple fact is the the JVM is where it's at in this respect. Paul On Jun 7, 2013 1:38 PM, "Brandon Bloom" <brandon.d.bl...@gmail.com> wrote: > Alexandru's analysis is spot on. > > Here's the pithy IRC version I've used in the past: "C# has a better type > system and compiler, so it doesn't need as good of a JIT. That's a problem > for languages that aren't C#, especially dynamic ones." > > There are lots of caveats, but that more or less covers it. > > On Thursday, June 6, 2013 6:53:05 AM UTC-4, Alexandru Nedelcu wrote: >> >> On Thu, Jun 6, 2013 at 12:47 PM, Colin Fleming <colin.ma...@gmail.com>wrote: >> >>> I'm not sure this is true, Don Syme has written several times about how >>> difficult it would be to implement F# on the JVM - I believe tail recursion >>> and not being able to define new intrinsic types (i.e. new primitives) are >>> the sticking points. >> >> >> Yes, both of these have been issues people had to confront on the JVM. >> However, for example tail-recursion in CLR not being used by C# meant that >> it went unoptimized and even broken on the 64bits CLR for years. >> >> Also, tail-recursion is not such a big issue, because self-tail recursion >> is easy to optimize by generating a simple loop (Scala does it, Clojure >> does it) and more complicated cases require indeed usage of trampolines. >> Not to underestimate their importance, being a useful feature to model >> state-machines, however you can still work by means of trampolines (Clojure >> elegantly solves it with syntactic sugar and it's workable in Scala because >> of it's good type-system [1]) >> >> On the other hand, the lack of support for new primitives has been >> hurting language implementations, like JRuby. Note that both features have >> experimental implementations as part of OpenJDK and it's possible we'll see >> them in the JVM. Plus, why stop at tail-calls? There are many languages >> that can hardly be implemented on top of both .NET and the JVM - not having >> continuations support, useful for Scheme or Smalltalk is a PITA. Haskell >> wouldn't be possible in either, because of it's laziness by default. You >> also mentioned primitive types, but for example the CLR lacks a Union data >> type, so implementing lazy integers for example comes with a lot of >> overhead. >> >> >>> I think a lot of people believe that from a functionality point of view >>> the CLR is better than the JVM - as far as I know it's not missing any >>> functionality from the JVM and it has significant advantages (reified >>> generics as well as the functionality mentioned above). >> >> >> That's not true. It does have a couple of advantages (like the ones you >> mentioned), but that list is shrinking and the advantages that the JVM has >> are huge and the list gets bigger with each new release. >> >> Reified generics are actually a PITA for new languages. Scala's generics >> are much more flexible, with a much better design than the ones in Java - >> you cannot implement Scala's type system on top of .NET's generics without >> cutting down on their features. Erasure is not bad per se and for the >> utility of reified generics, it really depends on what language you're >> talking about. Erasure has only been bad for Java, because Java's type >> system is too weak and because in Java the wildcards are used on the >> methods themselves, rather than at the class level, which has been a big >> mistake. Also, Scala's type system is much stronger, much more static and >> much more expressive. I never felt the need for reification in Scala. It >> even has the option of doing specialization for primitives, to avoid >> boxing/unboxing, as an optimization option. Haskell also implements >> generics by erasure. >> >> Reified generics are bad for other languages if you need to workaround >> them. For dynamic languages it's somewhat a disaster. On the JVM the >> bytecode is pretty dynamic, except for when you need to work with >> primitives (for invoking operations optimized for primitives) or when you >> call a method, you need to know the interface it belongs to (something >> which changed in OpenJDK 7 with invokeDynamic). Otherwise you don't have >> static types in the actual bytecode (e.g. casting an object to something is >> just an assertion in the actual bytecode that you don't need). But with >> reified generics, suddenly you have more static typing you need to take >> care of and avoid. >> >> When generating bytecode it's easier on the JVM. The final packages >> (Jars) are just Zip files containing .class files, with a text-based >> manifest. The .class files themselves contain the debugging symbols and >> those debugging symbols are part of the standard spec, whereas the format >> for the CLR was never a part of the ECMA standard, was private and for a >> long time Mono has been using their own format for those debugging symbols, >> as they had to slowly reverse-engineer whatever Microsoft was doing. >> Because Java libraries tend to use a lot of bytecode-generating routines, >> the tools available for that are amazing (like ASM), whereas on top of .NET >> things like System.Reflection.Emit takes care of only a subset, so the Mono >> people had to come up with their own alternatives (like Cecil). For the >> parsers, you can use mature libraries such as Antlr, at least for the >> initial prototype. Speaking of Antlr, it does have a C# generating backend, >> but it's a poor and badly maintained port. >> >> The JVM is awesome in what optimizations can do at runtime. VMs have a >> tendency to be optimized for their primary languages. In C# methods are >> final by default, whereas in Java the methods are virtual by default. This >> seemingly small and insignificant issue meant that the JVM needs to >> optimize virtual method calls at runtime - so the JVM can inline such >> virtual method calls, while the CLR cannot. The C# compiler is where most >> optimizations happen, whereas more and more optimizations have been move in >> the JVM itself at runtime ... Scala code runs as fast as equivalent Java >> code, even though the compiler is much newer and immature. The JVM can do >> other runtime optimizations as well, based on actual profiling and >> heuristics. It can do escape analysis to eliminate locks, if it sees that a >> short-lived object doesn't escape its scope, then it can allocate it on the >> stack instead of the heap (as a result of Java not having the ability to >> define new stack-allocated values). If an optimization isn't performing >> well, then it has the ability to deoptimize that piece of code and try >> something else. InvokeDynamic from JDK 7 gives you the ability to override >> the normal method-dispatch resolution. So you don't need to know the >> interface of a method when calling it. And such dynamic calls get the same >> optimizations as normal virtual method calls. This reduces overhead for >> languages such as JRuby. >> >> The JVM has been used a lot in a server-side context. This means >> long-running processes that generate junk and that must have near-realtime >> low latencies. This means a lot of effort has been made to build garbage >> collectors that cope with such workloads. As a result, you have the >> concurrent mark-sweep GC (CMS), the new G1 from JDK 7 or Azul's Pauseless >> GC (expensive, but amazing, or so I hear). Alternative languages (such a >> Scala, JRuby or Clojure) tend to generate a lot of short-lived junk. And >> JVM's garbage collectors can cope with it efficiently. >> >> I can probably think of other stuff, but this email is already too long >> :-) >> >> [1] http://blog.richdougherty.com/**2009/04/tail-calls-tailrec-** >> and-trampolines.html<http://blog.richdougherty.com/2009/04/tail-calls-tailrec-and-trampolines.html> >> [2] >> http://www.artima.com/lejava/**articles/azul_pauseless_gc.**html<http://www.artima.com/lejava/articles/azul_pauseless_gc.html> >> >> -- >> Alexandru Nedelcu >> https://bionicspirit.com >> > -- > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/groups/opt_out. > > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.