Paul Graham liked to blog about how awesome Lisp is. Apparently, he did some web back-ends in Lisp and was able to stay ahead of the competition. Now, Lisp has some awesome features. The two that stick out to me are (a) Lisp macros, which are arbitrary Lisp code run at compile time that emits arbitrary Lisp code that gets compiled, allowing some seriouly powerful constructs to be created very concisely and (b) massive libraries. That being said, I suspect that Paul Graham and his cohorts were more successful at using Lisp compared to another back-end language because they were both very skilled at the language and also super smart. The language they chose is actually MUCH less important. If they’d chosen another language, they would have done probably just about as well.
If you’re not a super smart programmer, I recommend Java (among other languages). Pass-by-reference and garbage collection obviate a lot of coding mistakes. And with Jit compilation, you get pretty darn fast code. Under 99% of circumstances Java performance is way better than adequate and makes MUCH better use of programmer engineering time.
But if what you want is super fast performance, a super smart C++ programmer will beat a super smart Java programmer. It’s a lot HARDER to get better results from C++, but the ceiling is higher. Some reasons for this:
- In memory-constrained environments, garbage collection imposes some overhead. I’ve worked on huge programs near the VM size limit whose performance was limited by GC performance. Most of the time, incremental GC in another thread is a win, but it can be a huge liability in memory constrainted environments. Instead, manual memory management in C++ allows you to make tighter use of the memory space and performs better in a memory-constranied environment.
- In a CPU-constrained environment, background GC steals cycles away from computation.
- Just like how macros are a huge win in Lisp, C++ templates generate customized code at compile time that can have huge perfrormance benefits. This is why C++ sort is faster than the C library qsort: The C++ sort is a template that inlines the comparison function for the type you’re sorting, rather than making a method call. In Java, you MIGHT get some of this from a fabulous JIT compiler.
- Compiling to bytecode is a huge information loss. If you used gcj to compile Java to native code, there’s the potential to have less information loss and therefore optimize better based on the programmer intent. But normally, Java uses bytecode as an intermediate. With more programmer intent knowledge, the C++ compiler can make smarter optimizations.
I could add more things, but I have other real work to do. Before I go, I’ll cap this off with two practical thoughts. You CAN get better performance from C++ than Java. Do you WANT to?
- Java has massive libraries too, where the critical parts are written in optimized native code, so if you make heavy use of Java libraries, you’ll see almost no difference in performance with regard to CPU throughput (GC being a separate issue). With no perceptible impact on peformance, less code to write, fewer common programming errors, and better use of engineering time, Java is quite often just an all-around practical win over C++. I say this as a programmer who prefers C++.
- If you’re REALLY REALLY concerned about performance, use Fortran. The language is more restrictive, providing the compiler with even more freedom to optimize. (For instance, no aliasing, no recursion.)