- enhanced for loop (foreach in C#)
- varargs (variable argument lists - "params" in C#)
- annotations (much like .NET attributes)
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.
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.
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
- 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.)