Hejlsberg Talk About Generics in C# and Java
An anonymous reader writes "artima.com has a very interesting interview with Anders Hejlsberg - the Borland guy now at Microsoft who can best be defined as MR C# - doing all the stuff that Borland wouldn't let him do. He discusses generics in C#, Java (1.5) and C++. Naturally there is the chance of bias but he does raise some interesting points againt Java's generics. Specifically that Java's genericised collections will have to box all primitive types as full objects, whereas C# does not. This is a big performance plus for C#. Java created the primitive types in the first place to address performance concerns but appears to be stepping sideways here. I can't help wondering if Sun has taken this approach to get the syntatic sugar in the language without requiring a bytecode change, but perhaps in a future VM version will allow primitive generics (obvioulsy forcing a bytecode regeneration)?"
Primitive types are boxed in C#, just automatically wrapped and unwrapped as required. But what he seems to fail to realise is that Java 1.5 is introducing this too, so that I will be able to define method(Object obj) and type method(12) and will receive a boxed Integer type. This should work fairly for generics too (I hope).
I'm a Java developer of 4 years and I'm unimpressed by generics. Why have all those 's dirtying up my code, only to enforce strong typing on my collections? If strong typing is really important, I can create my own strongly-typed collection. Otherwise, there's something called GOOD CODING, along with runtime exceptions, which enforce it. I don't see the need for all that extra ugly syntax just to enforce it at compile time.
reech bee-yond ur clip-0n
Just read a little further into the article. It seems that to avoid having to make changes in the VM, the Java generics have to become just like the current containers at the bytecode level. The main difference would be taht instead of having to type all the ugly type casts yourself, the compiler would do it for you. Obviously, this doesn't lead to any performance increases over Java 1.4 containters.
Compare this to, let's say, C++ templates, where the compiler makes a new copy of the template class specifically for each and every type you use on it. That makes the executable size increase a bunch, but it allows the compiler to pay the performance price, making the code perform almost like a program where a human programmer would have written a copy of the template class for each and every type you ever used it with.
Since the design of the java 1.5 generics is public knowledge, it's pretty easy for anyone with a reasonable programming knowledge to analyze it. It just seems that run-time efficiency wasn't the first thing in the designers minds.
"Just read a little further into the article. "
pfft. right. Like I'm going to read an article before commenting on it.
People complain about the dumbest things. I always laugh when someone complains about the performance of java. Guess what, if your app needs to be high performance, you shouldn't be doing it in java. If it doesn't need to be high performance but it needs to run on every os and computing device under the sun, then you should use java.
Programming languages are tools. Hammers for nails, screwdrivers for screws, C for hardcore big stuff and python/perl for everyday fun. Java was never intended to be high performance. It was intended to let you run a program on every single device and operating system there is, and have it run almost identically. The fact that java is as high performance as it is now is amazing. If you need performance and java isn't cutting it maybe you should ask yourself "why am I using a screwdriver to put a nail in this piece of wood?"
As for the specific issue of genericising and java's collections. I think java's collections rule. Sure you can't make a collection of primitive types, big deal. You can make an array of primitive types. And you can even make your own class, which inherits from collection and is in fact, a collection of primitive types. But just about everything in java is an Object anyway. So an ArrayList or a LinkedList are good enough 99% of the time. You keep on coding in C#, and when the world doesn't use windows anymore we'll see if your app is still around.
The GeekNights podcast is going strong. Listen!
This is just my interpretation. I'm not a C# developer:
Its faster because C# ints don't have to be converted. They are already objects (more like second class structure-like objects). When you define a collection of ints in C#, there is no boxing needed to populate the collection.
You are right about Java, however. The byte code looks the same if you use generics, or not. There won't be any performance loss from old code, just better looking code.
What the article is saying, is that adding primitives to a collection is slower than adding objects (due to boxing - automatic or otherwise). This is supposed to negate the benefits of using primitives (rather than objects) in Java.
I read the article to see what the numbers were on performance differences. Turns out there were none, what a surprise! So as usual, in theory, perhaps maybe there might be a performance difference and maybe it might be significant or not, or both. Until real comparisons are made, safe to ignore.
What's more important is his other problem with Java generics which is that in runtime it's not possible to tell what type a collection is compiled as, this is to retain bytecode compatibility. So reflection will have no clue on any of this generics stuff, which isn't a deal breaker, it's just a downside I hadn't heard about before.
where it makes sense, but we are also very
conscious about not sharing where you want
the performance.
Welcome to the Microsoft business model. :)
I've been reading through the various segments of the interview, and I tend to buy most of what Hejlsberg says on various Java vs. C# issues.
But I keep coming back to the idea that the changes (or improvements) aren't enough. If you accept that all of the changes are improvements, that they make things better, they're still not enough to justify getting locked into a single vendor, or in learning new libraries.
C# cleans up some of Java's annoyances, which is great, but the annoyances just aren't big enough to make the shift worthwhile. That's the problem.
I think the libraries problem is huge for Microsoft. The java libraries are just getting to be so big, complex, and rich that it will be very hard to get people to move away from them.
I don't think that anyone says there aren't annoying things in Java, parts of it that wouldn't be done differently if the language could be redesigned from scratch. But those annoyances are liveable -- for the most part, you can deal with them.
Java's has those libraries, though, and one of the reasons the libraries are so rich is that Sun opened up the process to other companies. MS is huge, they have a lot of smart guys, but I just don't think they can compete with Java's comparative openness.
That's the thing -- you can read about checked exceptions, and agree that it would be nice if java handled things more like C#, but it's not even close to being enough to overcome the value of java's openness vs. Microsoft's closed approach.
In the end, it really comes down to the business model.
C# generics are smart enough to treat value types differently than reference types (or what you're calling a "first class Object"), while Java generics are not.
The types of performance problems you're talking about are orders of magnitude away from the performance problems that users percieve when using Java applications though.
.NET framework use native code libraries for the GUI. It will never have the same perception of "slowness" that java has.
I disagree here.
Think of Moore's law, processor speeds, etc... Java is a fast enough language for doing just about anything a user needs to do. Even if java were only 25% as fast as native code, that would be 2 cycles of Moore's law, 36 months, 3 years ago. (And, java is much faster than 25% of C, check here)
3 years ago, users were all doing the same things they are doing today.
A couple of exceptions apply, of course: scientific computing, games, etc, tax the hardware pretty heavily.
But, the primary reason that Java is perceived as slow by users is the terrible speed of the GUI.
All the widgets are implemented in Java directly. This is almost like the same exception as game software, since all this rendering code involves moving around lots of memory, etc...
The GUI matters more than anything to user perception of slowness.
An old 14mhz 68000 amiga often "felt" faster than a 50mhz 386, because the amiga's os/gui were very responsive, while the 386 was running win3.1
Look at the recent developments with the linux kernel. Compare X responsiveness with a preemptible low-latency kernel, and how the whole machine "feels" better.
By going with preemption and low-latency, the overall throughput of the machine is actually slightly slower. But it feels loads better.
C# and the
It doesn't have anything to do with autoboxing in Java, but it has everything to do with boxing in Java versus C#.
Both C# and Java require boxing if you want to put an int into an object variable. They differ in whether that boxing is automatic or not (at least until Java makes it automatic in 1.5), but that's irrelevant: it still happens, so the performance impact is the same in both languages.
However, if you're trying to put that same int into an ArrayList<int>, the two languages are very different.
In Java, ArrayList<int> is really just ArrayList<Object> under the covers, and stores its contents into an array of type Object[], so the boxing operation still needs to happen. Hence, there's a performance hit.
In C#, ArrayList<int> is interpreted as such at the runtime level and the JIT compiler creates native code for it that stores the contents in an array of type int[]. When you store values into that array, no boxing is needed, automatic or otherwise. No performance hit.
Both C# 1.1 and Java 1.4 collections can hold primitive types if you box them. In Java 1.5, you get some extra syntactic sugar (which C# had from day one) but the boxing still happens. In C# 2.0, generic collections can hold primitive types without boxing. That's the difference that he's trying to get across in this article, and why it's specific to generics.
All of this is explained very clearly in the article and it amazes me that so many people can't grasp it...
I'm afraid you are wrong.
While "int" is treated "as if" it were an Object in the CLR, and behaves as if it was a subclass of Object, it really is a value type: It's allocated on the stack, cannot be subclassed, and is passed by value when it's used as a method parameter or return value.
The same goes for all the other built in primitive types (float, decimal, double, long, short, bool, char etc), along with user-defined Structs and Enums. These are all considered "Value Types" in the CLR.
When instances of value types need to be treated as Objects, they are boxed, just like in Java, except that it's transparent and automatic and there's no separate class that represents the boxed type - the distinction Java makes between int and Integer simply doesn't exist in C#. (System.Int32 is just an alias for int and isn't equivalent to Integer at all in any way).
The article clearly states that in Generic C#, the JIT actually creates specialized binary code whenever a generic class is instantiated with a value type argument. It even uses the example of List<int> turning into int[] (remember value types like int can't be subclassed, so the subclass problem doesn't arise).
C# provides the "illusion" of no primitives, but it's certainly not true that everything's always boxed. It just provides a more elegant and flexible model of boxing than Java does.
I mean, how many value types are there already? So you get a couple instantiatians of the class instead of one. And if you are really worried about footprint, you can use only reference types in your list.