Slashdot Mirror


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)?"

22 of 128 comments (clear)

  1. Boxing in Java by Ianoo · · Score: 2, Interesting

    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).

    1. Re:Boxing in Java by drkich · · Score: 2, Interesting

      Yes, C# does auto-boxing for the user. However, his point was that the Generics will not auto-box the primitive inside of an object.

      So for instance if you have a List, you can not place an Integer with out unboxing it. Vice-versa, if you have a List you can not place an int into with out boxing it.

      However if you have a List you can place an int into it directly without boxing it.

    2. Re:Boxing in Java by jovlinger · · Score: 3, Interesting

      Automatic boxing and unboxing will be identical to manual boxing from a performance standpoint.

      I got the impression that C# could actually use generics to instantiate the array at type int, rather than type Integer with autoboxing.

    3. Re:Boxing in Java by Steveftoth · · Score: 2, Informative

      My bad, I should to have said that a Generic List is compiled at runtime into a seperate class by the JIT.

      Since in .NET CLR a List is actually compiled into a list that only holds ints (and not objects), it actually has a completly different codepath then a List or List.

      WTF are you talking about? The only way you're going to get an instance of a class that implements IList and only holds ints is to do this ArrayList intList = new ArrayList(); If you just choose ArrayList myList = new ArrayList(); you get a non-specialized version of the IList-supporting class. Me thinks you don't know what you're talking about.

      Here's what I'm talking about from the second page of the article, Hejlsberg says that there will be lots of class definitions floating around in memory.

      Bill Venners: How do generics work in C#?

      Anders Hejlsberg: In C# without generics, you are basically able to say class List {...}. In C# with generics, you can say class List {...}, where T is the type parameter. Within List you can use T as if it were a type. When it actually comes time to create a List object, you say List or List. You construct new types from that List, and it is truly as if your type arguments get substituted for the type parameter. All of the Ts become ints or Customers, you don't have to downcast, and there is strong type checking everywhere.

      In the CLR [Common Language Runtime], when you compile List, or any other generic type, it compiles down to IL [Intermediate Language] and metadata just like any normal type. The IL and metadata contains additional information that knows there's a type parameter, of course, but in principle, a generic type compiles just the way that any other type would compile. At runtime, when your application makes its first reference to List, the system looks to see if anyone already asked for List. If not, it feeds into the JIT the IL and metadata for List and the type argument int. The JITer, in the process of JITing the IL, also substitutes the type parameter.

      Bruce Eckel: So it's instantiating at runtime.

      Anders Hejlsberg: It's instantiating at runtime, exactly. It's producing native code specifically for that type at the point it is needed. And literally when you say List, you will get a List of int. If the code in the generic type uses an array of T, that becomes an array of int.

  2. Why Generics? by HaiLHaiL · · Score: 2, Interesting

    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
    1. Re:Why Generics? by the+eric+conspiracy · · Score: 2, Insightful

      Why have all those 's dirtying up my code, only to enforce strong typing on my collections?

      Because compile time errors suck much less than run time errors.

    2. Re:Why Generics? by Aniquel · · Score: 4, Insightful

      A couple different reasons, actually. First, as mentioned in the article, performance. If you're using generics (come on, call them templates!) and compile-time checking, then you don't need to do the dynamic casting at run-time (c# doesn't, according to the article).

      Second, don't scoff at compile-time type checking - I've run into problems on large java projects where there's been some confusion as to what, actually, has been stored in certain collections. Generics prevent this.

      It comes down to this: How much help do you, as a programmer, want?

    3. Re:Why Generics? by Naerbnic · · Score: 4, Insightful
      "To ask the question is to know the answer"

      The easiest response to that, is the point you just brought up. To get some semblance of compile time type checking, you'd have to make your own type. There are various disadvantages to this, among which are:

      • It uses up your precious time to do what should be almost automateable
      • You can't easily fit back your custom class into the standard classes Java would provide. Your derived class, for instance, would be returning class Foo instead of object. Java doesn't allow you to override methods that vary only by return type
      • Depending on naming, the new class may not be apparent to someone using your API to what it is, especially if your custom class is simply a wrapper around a standard class


      As for the benefits of generics, a basic one is that it makes the intent of the code clearer (since you don't want to make a custom type, for the reasons above). The other major one I can come up with right now, is making your interfaces clearer to people who would use your classes. By fully specifying the type (including what is supposed to be in collections), you can make sure the class user is clear on what the interface to a method is, and if he makes a mistake, the compiler will tell him. This means you don't have to deal with all the messy exception handling and such that would go along with just using Object base types.

      I am agreed that the < > syntax can be too verbose at times, especially with something like LongClassName<AnotherName> foo = LongClassName<AnotherName>(). Of course, this leaves us with a quandary, since on the one had we want to be able to easily see and specify types of everything, which would suggest using full typenames everywhere. On the other hand, we could introduce typedef like functionality, but that would have some problems of clarity. It seems that Java has historically, and still is taking the first approach.
      --


      So there I was, juggling apples and small animals, when I accidentally bit into the wrong one...
    4. Re:Why Generics? by Dr.+Bent · · Score: 2, Insightful

      If strong typing is really important, I can create my own strongly-typed collection.

      Sure you can. You can also write the Java bytecode by hand, in hexadecimal, using only your pinky fingers to type.

      The point of generics is to reduce (significantly) the amount of time it takes to create strongly typed collections. In addition, it makes those collections more reusable. For example, if I make a strongly typed Iterator, either I have to make an Iterator that doesn't inherit from the java.util.Iterator interface (meaning that it won't be compatable with classes that already use that interface), or I have to create a subclass that has two sets of methods (one strongly and one weakly typed) for every operation. Neither of those options are ideal. Generics provide a 3rd option that is much more elegant and safe.

  3. Re:Performance of generics by hibiki_r · · Score: 5, Insightful

    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.

  4. Re:Performance of generics by Frequanaut · · Score: 2, Funny

    "Just read a little further into the article. "

    pfft. right. Like I'm going to read an article before commenting on it.

  5. Can't Believe by Apreche · · Score: 2, Informative

    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!
  6. Re:Nothing's changed here... by bay43270 · · Score: 2, Insightful

    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.

  7. The other downside to java generics is worse by Matt2000 · · Score: 4, Informative

    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.

    --

  8. Oh, the irony! by joelparker · · Score: 2, Interesting
    ...we do fairly aggressive code sharing
    where it makes sense, but we are also very
    conscious about not sharing where you want
    the performance.

    Welcome to the Microsoft business model. :)

  9. C# vs Java by astrashe · · Score: 3, Insightful

    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.

    1. Re:C# vs Java by astrashe · · Score: 2, Insightful

      Thanks for the IKVM link. It looks like a pretty cool project, although the blog is a little over my head.

      But if I had a job writing software for large banks, or some other very serious group of people (I don't), I'd be afraid of using something like IKVM and Mono -- again, Java's annoyances don't seem annoying enough to push people that far out of the mainstream.

      Isn't the primary value of these sorts of projects in the learning?

      I mean, in order to follow the IKVM development blog, I'd have to be a much more knowledgable geek than I actually am. I'd be thinking about language syntax, what the compiler is actually doing, and what the VM does in much deeper ways than I do now. Presumably, that would pay big dividends when I regular old java code that would run on the boring old sun jdk.

      To me, it seems like knowing this stuff would be a much bigger win than the actual functionality these projects are trying to deliver.

      What I'm trying to say is that I have a tremendous amount of admiration for the people who actually build stuff like that, and I wish I was in that league, but I'm not sure that I want to use it.

  10. Re:Nothing's changed here... by the+quick+brown+fox · · Score: 2, Insightful
    In C#, no conversion/wrapping/boxing, whether manual or automatic, will be necessary. The parameterized type will actually store the values in their unvarnished, primitive form.

    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.

  11. Re:It does seem any "performance" argument is bogu by dustman · · Score: 2, Interesting

    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.

    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 .NET framework use native code libraries for the GUI. It will never have the same perception of "slowness" that java has.

  12. Re:Nothing's changed here... by sab39 · · Score: 4, Informative

    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...

  13. Re:Nothing's changed here... by sab39 · · Score: 3, Informative

    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.

  14. Class proliferation by Latent+Heat · · Score: 2, Insightful
    I think what is going on is that you will get a list class for each separate value type and then one list class that will hold all the reference types (the value type is sort of like pointer).

    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.