Thursday, July 12, 2007

What's wrong with Java

When I see the features added recently to Java, I'm sure glad I'm using .NET, C# and boo. Even though Java is a lot older than .NET, .NET seems to get the good features first. Care in point: Generics. For a former C++ developer, it seems stupid to give up type-safe collections; I don't know how many years it took before Java got generics (10?) but .NET got them in much less time (less than 4 years, I do believe) and Java was left playing catch-up. In fact, most of the "new" features in Java 5.0 seem to be things that C# had from the beginning:
  • enhanced for loop (foreach in C#)
  • autoboxing/unboxing
  • enums
  • varargs (variable argument lists - "params" in C#)
  • annotations (much like .NET attributes)
Java generics aren't even supported by the JVM, so you get the same performance penalty from casting that you did before. I've always been unhappy with Java's performance (especially for GUI programs), whereas .NET just doesn't seem slow.

Look, Sun, if nothing short of competition from Microsoft can prompt you to improve Java, you must not care very much much about it.

Let's see, what else...
  • Value types (structs). This is a big one for me because can offer a big performance boost in many situations. You don't want to allocate a new object if that object contains nothing more than an integer and some methods, do you? A new object sucks up at least 16-20 bytes of memory even if it just contains one integer or reference; creating it requires multiple method calls and all those bytes have to be initialized. Useful value types include
    • A "Point" type that has X and Y coordinates
    • A "FixedInt" type that contains a fixed-point number (the language must support operator overloading to make it easy to use, of course.)
    • A "BigInt" type that contains a small integer normally, but allocates a memory block for a large integer if necessary.
    • A "Handle" type that contains an opaque reference to something else
    • A "Symbol" type that contains a numeric identifier that represents a string (symbols are a built-in feature of Ruby and are typically used like enums, except they are more flexible)
    • A Pair type that contains a pair of values A and B; often you get better performance by not allocating memory for this purpose.
  • Multi-language support. Well, the JVM can certainly support multiple languages, but only .NET is specifically designed for it. Admittedly, the design isn't that great, but at Microsoft specifically considers the needs of other languages.
  • Delegates. The Java equivalent is using interfaces with one function in them, but this is relatively inflexible and certainly more annoying to use. Java provides inner (even anonymous) classes to help people use the pattern, but delegates are way better.
  • Closures (functions inside other functions, where the inner function can access local variables of the outer function). Java doesn't have that, does it? You can access "final" variables from a function-inside-a-class-inside-a-function, but that's all. By the way, .NET itself doesn't actually support closures, but C# fakes it well.
  • Iterators. Now this may be my favorite feature of C# 2.0; it would be hard to choose between iterators and generics. I love them not only because you can create enumerators easily (which is great) but also because you can approximate coroutines with them.
  • Swing. Ugh! It's ugly, it's slow, and the Windows "skin" isn't very convincing. There often seem to be glitches in Swing that you don't find in other programs, such as the failure to resize a window fluidly (i.e. the window doesn't redraw itself until you let go of your mouse button). Finally, and worst of all, developing Swing GUIs is a huge pain in the ass. I absolutely can't stand it. The .NET counterpart, Windows.Forms, doesn't seem all that well designed, but it looks good, it's relatively fast, and it's easy to write code for it. Plus, of course, a good Forms designer is a standard feature of any .NET IDE.
Right now I wish I could have the C# 3.0 "var" feature because I'm sick of typing

SomeJerkGaveThisClassALongName foo = new SomeJerkGaveThisClassALongName();

Obviously we should be able to write simply

var foo = new SomeJerkGaveThisClassALongName();

And there's a lot of other great stuff in C# 3.0 [.doc]:
  • Lambda expressions (syntactic sugar for anonymous inner functions) with type inference
  • Type inference for generic method calls
  • Extension methods (they are not well thought out, but I'd rather have them than not)
  • Object and collection initializers (to make code more brief)
  • Anonymous POD ("plain old data") classes, which work like tuples except that the fields have names.
  • And last but not least, the query thingie, LINQ.
Suddenly, C# is starting to seem a lot more like boo.

Having said all this, there are a couple of things from Java that I might like to have in C#:
  • The assert statement. Typing Debug.Assert() all the time is driving me nuts.
  • Inner classes that have an implicit link to the outer class
And let's see, if I could have some more features I think they would include
  • Traits
  • The ability to supply a default implementation for a member of an interface
  • Preconditions and postconditions on methods
  • Static and run-time unit checking (units as in metres, litres, bytes, pixels, etc.)

3 comments:

Neal Gafter said...

By my calendar Java was released with generics before C#.

Johannes Luber said...

Regarding interfaces with default implementations: Why don't you define an abstract class, which implements the interface? That way developers can choose what is more suitable to them.

Qwertie said...

Neal, you may be right. I don't know how to find the dates, though BTW there were proposals for generics in Java since before C# was created.

Johannes, of course people routinely do this. But very frequently you have some other class as your base class and you just want to add another interface to what you already have. If the interface you want to add is heavyweight, like IList>T>, it would help to have default implementations for most of the methods.