Introducing Java

2007-05-17, , , , Comments

I didn’t get to use Java until relatively recently in my programming career. As a C++ programmer brought up on C, I suppose I suffered the usual prejudice: that Java would be a feeble language designed to stop feeble programmers from getting hurt too badly. The truth turned out to be rather different.

Garbage collection

One headline difference between Java and C++ is of course garbage collection. On the face of it, C++ provides the best of all worlds: there are techniques to precisely encapsulate resource lifecycle; there are libraries you can get hold of to collect garbage for you; and, finally, it looks like C++09 will include garbage collection.

The sad truth is that the techniques I mention aren’t as widely used as they should be. It’s hard to blame C++ programmers because the various smart pointer classes haven’t yet been formally standardised and most C++ books fail to mention them (and the one smart pointer which did make it into the standard library is notoriously slippery). So we’ll have to wait for C++09, roll our own, or get hold of a TR1 implementation — and without considerable discipline there’s nothing to stop rogue programmers on the team using new and delete as a high-level interface to heap management.

Garbage collection doesn’t release programmers from thinking about the way a program uses resources, but it sure does release us from some tiresome defects. Running a program though valgrind (or similar) doesn’t prove it’s clean.

Runtime Errors

Similarly, Java throws runtime errors as soon as it detects problems C++ may not even notice. If you try and read past the end of an array or access a non-existent object, the runtime signals the error soon as it happens. No need for forensic investigation to figure out what trashed the stack.

The C++ counter-argument is that this kind of checking costs. You have to be pretty dumb to try and read past the end of an array, so why ever pay for a safety check on every array access? It only took a couple of ArrayIndexOutOfBoundsExceptions to disabuse me of this notion. Dumb checks save time, especially the ones the programmer doesn’t have to write; excluding them on the grounds of perceived cost counts as premature optimisation.

Verbosity

Unfortunately, though, if you write Java, you usually have to write a lot of it. I’ll repeat Paul Graham’s joke about the Java implementation of “Hello, World!”.

Hello, World!
public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

Someone who has never written a program probably looks at this and wonders, why do you need to say so much to get the the computer to print a message? Curiously, the reaction of experienced programmers is identical.

An IDE will write a lot of this for you (and Java is rightly famous for its associated IDEs) but you’ll still have to read it every time you visit the file. Programs are read more often than they’re written.

The March of IDEs

I’ll admit that refactoring IDEs can be useful. If you have to use Java, use a refactoring IDE to keep your code in shape. The relative simplicity of the Java syntax and compilation model means that a Java IDE is always going to be one step ahead of a C++ one for this kind of thing.

While we’re on the subject of IDEs, I’ve also noticed some grumbling about the lack of such IDEs for high-level dynamic languages such as Ruby and Python. If a variable’s type isn’t declared when a program is being written, how’s an IDE going to auto-complete the methods supported by that variable? I’m not an IDE designer, but the solution to this would seem to me to be to merge the interpreter and the editor: that is, run and write the program at the same time. If I’m in the Python interpreter, I can just use dir to tell me what’s available.

In Java, everything is an Object

Everything except the built in types, that is. Java couldn’t quite go the whole way: if it’s going to compete with C and C++, it’ll have to measure up on performance, and that seems to mean fixed-width built in types. At least Java does have and always has had an official eight byte long integer, meaning that, for example, millisecond clock values won’t wrap in the lifetime of this planet.

The downside of making everything an object is that few application domains can be modelled in this way. Sure, a windows-based user interface maps nicely to an object hierarchy, but when you get into the core application engine, you’re likely to find yourself mapping, filtering and reducing collections — a more functional style programming. C++ provides far more power here: I’m reluctant to say it does better, because any heavy use of the STL and templated code requires lengthy build times and a willingness to unpick hideous compilation errors.

Compilation

Java is much much quicker to compile than C++. You don’t have to worry about dependencies the way you do in C++. A modern Java IDE compiles as you type and can even run unit tests on the fly (though I never quite got into this myself). Even better, once you’ve compiled the code, it should run wherever you’ve got a suitable JVM. Java abstracts the platform nicely enough.

The flip-side of this is that, if you need to dig beneath the JVM and poke at the system level, you’ll have to work harder. The JNI is fiddly to use and not documented to Java’s usual high standards. Of the low-level languages, C and C++ have the edge here; and high-level languages built on the C hardware abstraction layer such as Python and Perl fare better.

Libraries

With Java, if you’re doing something someone’s probably done before, they probably have done it before and made a suitably licensed library available. I was very impressed with the range and quality of Java libraries. The fact that Java has a standard and widely followed set of coding conventions makes it easy to work with these libraries, as does the Javadoc documentation system and the JUnit test framework.

Javadoc

Javadoc may seem like an incidental detail. It’s not part of the core language and you don’t need to use it when writing Java. The truth is that Javadoc is a defacto standard — so much so that it’s cloned itself into Doxygen, which does a similar job for C++. Not everyone likes the documentation template which Javadoc imposes but few would complain at the end result: a coherent, consistent, hyper-linked documentation suite, and simple tools which allow you to generate your own documentation in the same format.

JUnit

JUnit, like Javadoc, is a defacto standard — a simple and well-documented test framework with great tool support built around it. Again, it’s been cloned into other languages even when they don’t naturally support such a framework.

Java versus C++?

Java versus C++ for what exactly? As a general purpose programming language for doing XML-y database-y user-interface-y internet-y things, Java has the edge. Then again, C# probably has the edge over Java in this same domain — it certainly should do since it’s had the opportunity to learn from Java’s mistakes, and it surely has enough brains and backing behind it. I don’t speak from experience: I’ve never used C# and I don’t see any pressing need to use it. In fact, I don’t see the need to use Java. I’m convinced that high-level languages such as Python knock the spots off Java and any Java clone in the application development domain.

As a general purpose programming language which needs to mix low-level platform access and high-performance algorithms, C++ is probably still where it’s at. If you’re prepared to invest the effort to learn it (which I wouldn’t recommend!) then I’d say C++ is a more expressive language than Java. I’d rather be able to overload operators than have to put all my functions in classes. Structs beat beans.

The JVM Platform

Java welcomes high-level languages. Just put the Java “J” in front of Python, Ruby, … and you’ll find an implementation of your favourite language running on the JVM. Then there are the JVM natives such as Groovy and Scala and no doubt many others. Russel Winder comments:

What about Java? It survives as the assembly language for Groovy programming.

Language Wars

Reading through all this, I realise I’ve not said anything radical or original. At the outset I declared myself “a C++ programmer brought up on C” — which is pretty much what I was doing when I first encountered Java (though my not-so-secret mission was to write code using high-level languages). The truth now is that I’m actually a Python programmer brought up on C/C++, and as such, anything which might have seemed radical or original about Java seems, well … ordinary and bland.

Certainly I’ve been cured of any prejudice about Java being a feeble language designed to stop feeble programmers from getting hurt. It’s the other way round; Java is a powerful language and it’s the C++ programmers who revel in pain.

It took me about a year to get round to writing this note, a year in which I’ve barely touched Java. I haven’t missed it.

Feedback