|
Hm... I'm not trying to argue with you, you're right that I only have a superficial overview of the Java/JVM/J2EE ecosystem, but I will try to elaborate on the points of my original post, which was rather sparse, I admit. As I read Wikipedia, HotSpot is opensource. I'm not sure if that includes the best JIT compiler (what the JVM is known for) as well, or if that's still closed/proprietary, but I'd be pleasantly surprised if it's open source as well. Still, we have the patents issue, i.e. the current legal battle between Google and Oracle. Releasing the source but suing anyone who uses it is not the way to do open source, IMGO (true, the source was release by Sun, and Oracle is the one who's suing, but still). I believe that a general purpose programming language (suitable for business applications) has to be able to perform as well as C for heavily optimized code. What I mean is that you have to be able to write algorithms that run very fast. You can probably do that with C# (supports unboxed structs) and maybe even Objective-C (supports MemoryPools, and method lookup caching), but not Java (AFAIK). Sure, you can always link to external C libraries, but then you have to face dependency hell and portability issues. The issue that I see with Java's concurrency model is not that it is not powerful enough, but that it is too powerful. It allows synchronization on any heap-allocated object, which probably has a lot of overhead (used to be performance overhead, but HotSpot was heavily optimized for that, so after a lot of programmer-hours overhead, the performance overhead was lowered). However, I think that this kind of threading model is not scalable to massively parallel/distributed environments. Synchronization/sharing will have to be limited, e.g. as in Erlang/WebWorkers/Rust, using GCD in Objective-C, using MVar (Haskell) or transactional variables (Clojure). Java probably can never do that, without sacrificing backwards compatibility. Lack of support for functional programming was meant more on the JVM level. There are no tail calls, no fast object allocation, no true polymorphism, and I'm guessing that since closures have to be represented as objects, they are not particularly cheap. |
The patent issues are regarding Dalvik AFAIK, so I don't see how it's relevant to this discussion ... (although, from what I've heard, it seems like Oracle's being a jerk ...)
If you think that a general purpose language has to be able perform as well as C without calling native code (JNI, FFI, etc), I guess I'd have to agree Java isn't 'general purpose' . But I'd contend neither are Python, Ruby, Erlang, Javascript, etc under that definition. Therefore, that's probably not the right definition, since it excludes most general purpose languages ;-)
Being able to synchronize on any object is actually really efficiently implemented (8 bytes of Object overhead total, neat optimizations like biased locking, etc). And, if you don't want to share state between threads, Java can do pretty clean actors/message passing (http://doc.akka.io/docs/akka/2.0/java/untyped-actors.html) or transactional variables (AtomicRefs are built in). Java concurrency does give you the ability to shoot yourself in the foot if you use it wrong, but so will any sufficiently powerful tool.
Re the JVMs support for FP:
- JVM7 added an InvokeDynamic instruction which I believe addresses your polymorphism concerns.
- It sucks that there isn't a bytecode instruction to allow TCO. But, in practice, many JVM languages will convert recursion to iteration at compile time with constructs like http://clojure.org/special_forms#Special%20Forms--(recur%20e...
- What do you mean by 'fast object allocation'? I'm not familiar with the term ... Creating objects is fairly fast in Java though. A quick test suggests I can alloc around 200 million objects per second on the heap once the code path is JIT'd on my laptop. Incidentally, it's surprisingly tricky to fool the JVMs escape analysis and force a heap (not stack) allocation, without introducing too much extra work in a microbenchmark ;-).
- AFAIK, you're right that closures require an object allocation - but how else would you do it? When I was writing Common Lisp, we had to avoid creating closures in tight loops for the same reason