views:

4726

answers:

10

I have been a Java developer for 14 years and have written an enterprise-level (~500 kloc) Swing application that uses most of the standard library APIs. Recently, I have become disappointed with the progress that the language has made to "modernize" itself, and am looking for an alternative for ongoing development.

I have considered moving to the .NET platform, but I have issues with using something the only runs well in Windows (I know about Mono, but that is still far behind Microsoft). I also plan on buying a new Macbook Pro as soon as Apple releases their new rumored Arrandale-based machines and want to develop in an environment that will feel "at home" in Unix/Linux.

I have considered using Python or Ruby, but the standard Java library is arguably the largest of any modern language.

In JVM-based languages, I looked at Groovy, but am disappointed with its performance. Rumor has it that with the soon-to-be released JDK7, with its InvokeDynamic instruction, this will improve, but I don't know how much. Groovy is also not truly a functional language, although it provides closures and some of the "functional" features on collections. It does not embrace immutability.

I have narrowed my search down to two JVM-based alternatives: Scala and Clojure. Each has its strengths and weaknesses. I am looking for opinions. I am not an expert at either of these languages; I have read 2 1/2 books on Scala and am currently reading Stu Halloway's book on Clojure.

Scala is strongly statically typed. I know the dynamic language folks claim that static typing is a crutch for not doing unit testing, but it does provide a mechanism for compile-time location of a whole class of errors. Scala is more concise than Java, but not as much as Clojure.

Scala's inter-operation with Java seems to be better than Clojure's, in that most Java operations are easier to do in Scala than in Clojure. For example, I can find no way in Clojure to create a non-static initialization block in a class derived from a Java superclass.

For example, I like the Apache commons CLI library for command line argument parsing. In Java and Scala, I can create a new Options object and add Option items to it in an initialization block as follows (Java code):

final Options options = new Options() {
  {
    addOption(new Option("?", "help", false, "Show this usage information");
    // other options
  }
};

I can't figure out how to the same thing in Clojure (except by using (doit...)), although that may reflect my lack of knowledge of the language.

Clojure's collections are optimized for immutability. They rarely require copy-on-write semantics. I don't know if Scala's immutable collections are implemented using similar algorithms, but Rich Hickey (Clojure's inventor) goes out of his way to explain how that language's data structures are efficient.

Clojure was designed from the beginning for concurrency (as was Scala) and with modern multi-core processors, concurrency takes on more importance, but I occasionally need to write simple non-concurrent utilities, and Scala code probably runs a little faster for these applications since it discourages, but does not prohibit, "simple" mutability. One could argue that one-off utilities do not have to be super-fast, but sometimes they do tasks that take hours or days to complete.

I know that there is no right answer to this "question", but I thought I would open it up for discussion. Are there other JVM-based languages that can be used for enterprise level development?

+14  A: 

I think you need to ask yourself what your requirements are.

One seems to be that you are tired of Java's staleness. If true, this is an aesthetic objection to Java, and you should therefore pick either Scala or Clojure based upon which you prefer aesthetically (assuming all else is equal enough).

You also mention that you're disappointed with Groovy performance. Scala is basically as fast as Java if you want it to be (though it isn't always pretty when it is), and from what I've seen Clojure is not, at least not routinely. Does that really matter to you? Are you optimizing search query times, doing huge calculations on supercomputers, or otherwise requiring every bit of speed? Better use Scala; Clojure has yet to prove itself there. (Python and Ruby will also disappoint you in speed if this is the case.)

If you want trivial parallelization, it's hard to do better than pmap. One could add something like this to Scala, but it's not there out of the box--not yet, though improved support for concurrency/parallelism is planned for versions after 2.8. I don't know the state of Clojure's immutable collections, but it wouldn't surprise me if they perform better than Scala 2.7's immutable collections (that doesn't take much doing, I'm afraid), and if they've really paid attention (like the Haskell folks have), then they're probably even better than 2.8's. So if you're after parallel immutability, Clojure probably has the lead at this point--but benchmark to be sure.

Scala has been designed with a feature set that doesn't get in your way too much when you have large projects--flexible imports and package control and so on. For your Swing application, Scala wraps part of the Swing library in a much easier-to-use way. I can't speak to Clojure's strengths here, but it's worth considering that angle if you're planning on writing tens of thousands of lines of code in a complex project.

Anyway, I think the real point is that unless you require the very best performance (and refuse to drop back into Java for performance-critical portions of the code), you should decide based upon which you prefer aesthetically. If performance really is key, Clojure has not consistently shown itself to be as fast as Java while Scala has, so the answer is pretty clear.

Rex Kerr
Clojure has a number of optimization features (mostly consisting of type hints and use of primitives) that are rarely used outside of speed-critical code. In most cases, it is possible to produce exactly the same bytecode as the most-optimized Java solution. Such code can be a bit ugly, but a few hints in an inner loop is usually all it takes.
Zak
So I hear, but I haven't seen it reliably in practice, so I'm withholding judgment.
Rex Kerr
+38  A: 

I've been looking into that question myself, lately. What I've found so far:

  • Scala is very easy to get into, just because it's so similar to Java. It's very easy to start programming in a "Java-y" way and gradually ease into the functional programming style. Concurrency-wise, actors are pretty nice to work with. Also, the language supports many features that make it easy to create concise DSL-like features (of which Actors are a good example).

    On the other hand, Scala seems to me a very complicated language. The language, and especially the type system, is extraordinarily complex and I don't know what's going on inside it half the time. See this question on Scala collections for an idea of what I mean. (The question also has a very good answer by Martin Odersky himself, by the way.) Speaking of collections, I find interoperating between Scala and Java collections a big pain. You'll need to use implicit defs if you don't want to go completely insane; however, the implicit defs add another layer of complexity to the language where sometimes you don't know what's going on. I've heard people say that in Scala, you can just type whatever you like, and the compiler will find a way to make it do something. It's sort of like Java's C++: bolting the next big paradigm (functional programming) onto an existing language and adding all the language features that the creator could think of. I think Scala will be a very important transitional language, and I'm very much looking forward to its successor.

    Also, IDE support is not so good at the moment, unfortunately. The Eclipse plugin is almost unworkable. I hear that NetBeans support is ok.

  • Clojure is much simpler. It has almost no syntax and once you get over the parentheses thing, you'll find that it's a very beautiful, elegant and lightweight language. Interoperability with Java is very good, except for the drawback you mentioned. All collections implement the interfaces you expect, and all functions implement Runnable and Callable, so you can use them in the Executor framework or in Swing. Concurrent programming is very well supported, and Software Transactional Memory is an interesting concept that I intend to try in the near future.

    The biggest drawback, and also the biggest draw (at least for me), is the way it doesn't make compromises. You're forced to start thinking in a functional way, and you're forced to do it immediately. It completely changes the way you think about programming. This is a good thing, and you might even pick up a trick or two that you can use in Java, but it's also a slow and difficult process (at least, for me, having no LISP background). Clojure is very dense: it contains almost no boilerplate code, which is a good thing, but it also means it's harder to see familiar patterns in the code that help you understand things faster. It will take some time to become productive.

    IDE support is pretty good from what I've seen. But then, the language doesn't need a lot of support, as compared to Scala or even Java. You don't really need much except "rainbow coloring" for the parentheses :). (In the Eclipse plugin, be sure to deactivate "Paredit mode" from the settings, or you'll go crazy from not being able to backspace closing parens.)

So, depending on what you want to achieve, I'd have to give you a different answer. If you want to ditch Java right now and become productive immediately, go for Scala. If you don't mind continuing to use Java and taking some more time to learn something new, and change the way you think about programming, go for Clojure.



Update

Scala 2.8 was just released, and so was a new version of the Eclipse plugin. All the problems seem to have been solved; it works pretty well now!

jqno
I've not specifically used Clojure, but I find that looking at Lisp code makes it (eventually) *easier* to see patterns, since they fit on one screen. :-)
Ken
@Ken I hope you're right, and that I will one day reach that point too :).
jqno
The biggest problem that I sees with using Clojure is the resistance I'll get from my coworkers because the syntax is so "foreign" to developers accustomed to "C" derived languages. Scala is much closer. Having said that, in a sort of sick way, I like all of the parentheses in Clojure (I wrote about 1000 lines in Lisp in a former life about 30 years ago).
Ralph
Ralph: Tell them it's round XML.
Ken
@Ralph The parentheses forms boundaries. When your coworkers understand this, they'll start to like lisp. Also, as @Ken says :) Been working with Clojure for a year now. Very happy!
cschreiner
+3  A: 

Seems to me like you've just got a 14 year itch. So I'm going to suggest you avoid small improvements. In my opinion, there do not yet exist radical improvements in the Java line. If you want a lorry load of extra features, then sure there is C# and Scala leads a host of niche languages that aren't likely to go anywhere (IMO).

For my money, the only new interesting language about is Newspeak. However, that seems to not be getting the development it deserves, with Ahé and Bracha switching employers. For actually getting stuff done, for my money the pick of the rest would be Python followed by Ruby. Not new languages! Something to muck about with until something really new comes along.

Tom Hawtin - tackline
Do you speak from experience with Scala, Clojure, and the like, or as an interested observer? Personally, I have noticed a larger difference going from Java to Scala than I did from C++ to Java.
Rex Kerr
You are probably right about the "itch", but I can't help thinking that Java is getting passed by. Even C#, a younger "mainstream" language, has added such things as implicit types, lambdas, etc.
Ralph
@Ralph C# is a dialect of "Java-like language". IMO, it therefore makes no sense to say that C# is younger than Java. Compare C# 1.0 to Java of the time - not much difference.
Tom Hawtin - tackline
Just to get things straight - Gilad Bracha is still very much working on Newspeak, with the help of some volunteers, so it hasn't stalled. As a Java programmer of over 12 years myself, and also well acquainted with Scala, I join Tom's recommendation to check out Newspeak - it's object oriented programming in its most elegant form.
Yardena
@Yardenna Good to hear that.
Tom Hawtin - tackline
+4  A: 

This sounds more like you want to learn something new, than being tired of Java.

I would recommend learning Haskell which is available on most platforms but unfortunately not the raw JVM. They do a LOT of fun stuff while the functional thinking is so different from the step-by-step approach of Java that you will most likely learn a bit or two in the process.

I would also recommend mastering the new things in Java 6 as especially the concurrent stuff is so important for the new multi-core world that your programs will most likely benefit from it in the future. By the way, did you know that JavaScript is part of every moderne Java installation? What about learning that? And XSLT by the way, which is very useful in XML transformations. We use it directly from Java to post process web service results into something which is easier to handle programatically instead of walking around the DOM tree again and again.


EDIT: One of the most interesting things to come out of the JEE6 specification is the Dependency Injection JSR's, which basically allow you to delegate the "insert an instance of A into the variable of type A" gluing to a standard library. The reference implementation - named Weld - can also run in stand-alone applications, and allow you to basically say stuff like

@Inject org.slf4j.Logger log;

and somewhere else there is a factory which can initialize a Logger, which then just happens instead of you having to doing all the glue elsewhere manually in your own code. The concept is well known from Spring and Guice and others, but now has been standardized.

Thorbjørn Ravn Andersen
I have recently read both Josh Bloch's book "Effective Java" and Brian Goetz's book "Java Concurrency in Practice". I have started to use the java.util.concurrent libraries, although I can't say that I am an expert. I am aware of the Rhino Javascript engine in Java 6, but have not explored it very much. As I have been reading the books on Scala and Clojure, I have tried to incorporate some of the features back into my Java programming, making heavier use of Tuples and literal collections (using static factory methods and varargs).
Ralph
There is a functional Java website "http://functionaljava.org/", that proports to add many of the features found in functional languages to Java. I have not spent a lot of time looking at it, but I imagine that Java will still be just as verbose as it is today, even with added libraries...
Ralph
Haskell is interesting, but I'm not seeing there being much of future in using Haskell for enterprise GUI apps.
Tom Hawtin - tackline
@Tom, ah missed the "Ongoing development". So he wants to use this in production...
Thorbjørn Ravn Andersen
@Ralph, I believe the verbosity of Java comes from the naming more than from the syntax available (the for-statement helps, I'd like map and filter too - but that is a different issue). The naming convention encourages descriptive, long names and IMHO give a stronger foundation.
Thorbjørn Ravn Andersen
+10  A: 

Well, the short answer is that you have to try both of them. I think that they're both beautiful languages. (Full disclosure: I spend much more time playing with clojure.)

On the typing issue: clojure is dynamically typed. Since you're concerned about performance though, you'll probably find yourself putting type hints in performance critical spots. So your program will end up being dynamic in some places, and static in some places. I like that a lot, but Scala's type system is nice (though from my limited exposure, I prefer haskell.)

Persistent Data Structures So far as I know, both languages have persistent (immutable) data structures available. Clojure seems to have gone farther in making them an integral part of the language. I particularly like the transients feature -- introduced after the writing of Stu Halloway's book. The idea is that for situations where you need higher performance than even what you can get with efficient implementations of persistent data structures, you make a transient (mutable) copy of the data structure, do destructive updates on that, then return a persistent copy. (Actually, it doesn't even need make a copy of the data structure; it makes a copy only in the tree branches that have been updated, and those new branches are temporarily mutable.) Most of the time you probably wouldn't need this, but it's nice to have for performance critical situations. I think that Rich Hickey has really bent over backwards to make functional programming fun and easy.

Clojure and objects. Clojure doesn't really do objects, at least as we know them from java. (It can, of course, but that isn't really the goal.) In clojure, you're encouraged by the language to have functions, not bound to any object which operate on data, especially in the form of sequences. For one take on the object orientation issue, see Stu Halloway's blog post. Object like structures are defined using deftstruct or deftype, and methods on them are defined using multimethods or protocols, or just plain old functions. And in this particular area, the language does seem to be in transition. See this and other clojure google group posts.

Clojure's macros: This you have to try out. Clojure, I'd argue, will have the edge in meta-programming.

Scala may be the path of least resistance for a java programmer. There isn't quite as much of a culture shock, and the language has had a bit more time to mature. And Scala and Clojure really are on the "same side", in many ways. I hope that you'll give clojure a shake, though, because it has some pretty amazing features.

Rob Lachlan
I did not know about the transients feature, but I had planned on converting the persistent collections to Java mutable collections as stack objects (and therefore "immune" to corrupt by other threads), manipulating them, and then converting them back to Clojure persistent collections for the return values.
Ralph
As I read the Clojure book, I get the feeling that Clojure returns one to the older style "C" programming (procedural) paradigm that I left behind when I moved to Java, only with a functional "twist". That is NOT a criticism -- many times I miss C and wish I could write the simple programs I did 20 years ago.
Ralph
I have not yet reached the chapter on macros in Halloway's book, but I look forward to it. After learning Clojure, I will finally (after more that 25 years) be able to write Emacs macros :-).
Ralph
If macros in Clojure are the same as the macros Paul Graham describe in "Beating the Averages" (http://www.paulgraham.com/avg.html) it is very interesting indeed.
Thorbjørn Ravn Andersen
@Ralph: Yes, the analogy to C is very apt. Note that this idea works particularly well with immutable data. If you're not worrying about someone else modifying your data, it removes much of the need for walling off your data in private fields of objects. You don't waste any time writing getters and setters, etc. The approach isn't without its drawbacks, but I think its very powerful.
Rob Lachlan
@Thorbjørn Ravn Andersen: Yes they are the same macros (slightly altered due to the particularities of clojure syntax), because clojure is a lisp. So you get that ability to write domain specific languages within clojure very easily. It's pretty sweet.
Rob Lachlan
+18  A: 

I've been looking for a great JVM language to mitigate the syntax verbosity of Java.

But during the search, i've concluded that there are three classes of languages I think are needed and reasonable for my work-flow. They are (with the languages i'm using or considering or not and why):

  • For one-off scripting:
    • I use bash for relatively short scripts.
    • Python if it's a substantial script or just requires data structures. I really can't stand the spacing requirements of Python syntax but it's a great language otherwise. This spot used to be primarily Perl but i'm @$#% sick of @$#%. I want clean, readable syntax and Pythonic code is that, for me.
    • I'm considering JavaScript (Spidermonkey, not Rhino for this scripting) because i really like the direction JavaScript is going since 1.7 onward. And there's something really nice about cross-tier language homogeneity.
    • I'm not considering Ruby because it has always felt like a slightly (ok, significantly) better Perl but wanting to move away from Perl meant Ruby was caught in its wake.
    • I'm not considering any others because nothing has sparked my interest enough to replace Python.
  • Native, compiled:
    • Objective-C because i'm a Mac person and write for iDevices.
    • Go for all the reasons Google decided to create it in the first place. I think and hope it'll replace C and C++.
  • JVM:
    • Ioke because i think it most in-line with the language design i want. This language has such great potential. If it gets a good following, it'll be my choice, hands-down.
    • JavaScript (Rhino) for similar reasons as Spidermonkey and because of Nitro.
    • Groovy only because it has a nice syntax, is nicely integrated with Java and has an active community.
    • Scala is on my list because it's more complete than Ioke and has the functional capabilities JS and Groovy don't.
    • Clojure is in the running but i've written plenty of Lisp and i'm over the paren-balancing. Again, i want a clean, readable syntax and i don't consider nested parens readable. If it's not an issue for you, i'd put Clojure ahead of Ioke simply because of community support.

The bottom line for me is, i want to get things done. I love learning new languages but, more than that, i love using good languages well which means knowing the language well which also, at least for me, implies a strong community backing the language.

nicerobot
+1 for mentioning Ioke. Amazing language, that Ioke. I just wish it wasn't so godawful slow.
Rayne
Agreed. I think for the time being i'm going with Scala as my next Java while i keep my eye on Ioke. Performance doesn't seem to be one of Ole's top priorities at the moment but if more people get involved, others can concentrate on that aspect.
nicerobot
Doing manual paren balancing is a mistake. If you're using any kind of Lisp, a Lisp-aware editor is important. The "standard", if there is such a thing would be Emacs with Slime and Paredit. Of course, the learning curve for that tool set is probably steeper than the language itself.
Zak
@zak Agreed, which is why Clojure is still on my list and i can recommend it to others but i was writing tons of Lisp before modern Lisp-aware editors. The best i had was simple highlighting matching parens. So you can imagine the distaste for simply seeing the code. :) So, _for me_, unless i can overcome this deep-seated issue, Clojure doesn't stand a chance compared to Scala or Ioke. But otherwise, it's a wonderful language.
nicerobot
You wrote plenty of Lisp and never found an editor that took care of the parens for you (e.g. Emacs+Paredit)?
Michael Kohl
Too late for an edit... What I wanted to add: sorry, what I wrote before sounded ruder than intended. I guess I'm just surprised that you mentionend "balancing" as a problem. If you find parens hard to read, that's one thing, but the balancing should be done by the editor, not you.
Michael Kohl
My point is that i was writing Lisp in the mid-80s. Editors weren't as sophisticated as they've become (and if they were capable then, i never found them). If i was new to Lisp syntax today, i might be choosing Clojure instead of Scala (since Ioke is still too new and too slow). And recently, i've become really fond of new languages that work to eliminate extraneous tokens. That's just my preference. If others don't care about that, try Clojure. As i've said, my limited investigation of the language shows it to be quite good.
nicerobot
Go looks interesting, but maybe still a bit immature. For the time being, I will dabble around in Python to satisfy my curiosity for a non-Java programming paradigm.
Zsolt Török
+1  A: 

This is a fundamentally personal question though here's a real world experiment you can do: grab a small isolated class of your 500kloc program and replace it with the equivalent class written in scala and clojure. Perhaps this will give you an idea which one will be a better evolutionary successor. It will be a while before you see any really huge projects written entirely in either scala or clojure so perhaps you would find it useful to see which ones fit it's nich best while not getting in the way of the parts better done in java. Rich Hickey mentioned that Clojure was not intended to be everything to everyone, but rather to reduce the incidental complexity of writing certain types of programs. Scala is designed to take a lot of the keyboard work or of writing a large general class of programs.

Arthur Ulfeldt
+3  A: 

I strongly agree that the effort you put into a functional language will be rewarding. My favorite is Haskell, which is the language requiring the most effort, and which is the most rewarding. It will blow you away!

Scala elegantly captures a lot of concepts, just too many of them! The stated advantage of being able to write Java-like code in Scala is, in my opinion, its greatest deficit. If you really want to learn how to program functionally, try a function-opinionated language instead of one that lets you splatter mutability all over the place.

I'd like Scala better if its type inference was friendlier. Haskell is very strongly typed, but is very smart; you rarely need to write a type. Scala is fussy. You'll spend a lot of time resolving type issues. It has to be fussy, because it pulls classes into the functional paradigm.

I'm liking Clojure more and more. Simplicity is very important, more than is appreciated when you get into the weeds of a project. And Clojure really does encourage a functional style. Yet it's practical, allowing clean mutability and Java interop when really needed.

I'd hate for you to dismiss Clojure for want of an initializer block. (A feature of Java I'd forgotten all about!) The proxy function essentially defines and instantiates an anonymous class. I found two ways to add an initializer:

(opts-1) The methods you define in the proxy call can only override its superclass or interfaces. Any other methods you define there will not be callable like other methods, because they are unknown to the superclass (same as in Java). So to create a new Options instance with an initialization method, just inherit from Options and implement some interface containing just the method signature you need. You could define such an interface yourself in Java, or you could just misuse the Runnable interface. It has a single method, run, which takes no arguments and returns null. After instantiation, we can just call run to do the initialization.

(opts-2) Another, more direct, albeit slightly more verbose way to define an initializer is to just go ahead and define a new method. As mentioned, it will not be callable as a Java method because our proxy object's class is anonymous. However, Clojure does provide another way to look up the method, using the proxy-mappings function. It takes an object argument, and returns a map of method names to functions.

(add-classpath "file:///...YOUR.PATH.HERE.../commons-cli-1.2.jar")
(import (org.apache.commons.cli Options))


(def opts-1             ;; Define an instance of our Options subclass.
     (proxy [Options Runnable] []

       (run []          ;; Override Runnable/run (no args, returns nil)
         (.addOption this
           "?" "help" false "Show this usage information"))

       (toString []     ;; Override Options/toString
         (str "** opts-1 ** " (proxy-super toString)))))

;; Do the initialization.
(.run opts-1)


(def opts-2             ;; Define an instance of our Options subclass.
     (proxy [Options] []

       (initialize []
         (.addOption this
           "?" "help" false "Show this usage information"))

       (toString []     ;; Override Options/toString
         (str "** opts-2 ** " (proxy-super toString)))))

;; Do the initialization.
(((proxy-mappings opts-2) "initialize") opts-2)


(println opts-1)
(println opts-2)

This prints

#<Options$Runnable$36fc6471 ** opts-1 ** [ Options: [ short {?=[ option: ? help  :: Show this usage information ]} ] [ long {help=[ option: ? help  :: Show this usage information ]} ]>
#<Options$0 ** opts-2 ** [ Options: [ short {?=[ option: ? help  :: Show this usage information ]} ] [ long {help=[ option: ? help  :: Show this usage information ]} ]>

We see that the toString override worked in both cases. Also, the method call of run initialized opts-1 as desired, and so did the lookup and call of initialize for opts-2.

Tyler Perkins
I have just about finished Stu Halloway's (very nice) book on Clojure (2 pages left to read). I like the language, but my bias against dynamic languages for enterprise projects is holding me back. I know that static typing is no substitute for good unit testing, but it really bothers me that the only indication of the meaning of a function/method parameter is its name and any included docs. (Asbestos suit is firmly in place :-)).
Ralph
@Ralph - a good counter to that is the fact that you can very easily test out a function at the REPL to see what it does. It's also common for multimethods to dispatch on the types of arguments, which is another source for discovering what types of arguments might be valid.
Zak
I understand that it is not difficult to discover the correct parameter types. It is just that you must produce test cases to check that your code is doing so.
Ralph
+1  A: 

Rich Hickey (Clojure's inventor) goes out of his way to explain how that language's data structures are efficient

Well it's easy to have a look at the clojure datastructures. They are all plain old Java Classes. Here is the Github repository:

The PersistentTreeMap is a self balancing red-black tree implementation for example.

I have seen these. I hope that Scala adopts some of the Clojure data structures and STM in the future. Phil Bagwell is now part of the Scala team at EPFL.
Ralph
A: 

if you're looking for multiplatform alternative and greater performance than java, scala, clojure, and all those JVM based language.

I would like to suggest an alternative, which is C++ + Qt Qt is multiplatform, even supports embedded devices.

technomage
read the full question again, it specifically refined the requirement to a JVM language
Kevin Wright