Udostępnij za pośrednictwem


Some of my opinions on Generics

Disclaimer: These are all my opinions, so don't take them to mean anything more than the futile thoughts of an insignificant bystander who happened to be fortunate enough to listen to a few of the C# language design meetings and occasionally interact with some of the designers.

John and a few others have compared the CLR's generics (hereafter referred to as simply 'Generics') to C++'s templates ('Templates'). In some ways I think this is beneficial, but in other ways I think it is like comparing apples and oranges. This is my attempt to compare and contrast them and explain why I think certain comparisons are invalid.

  • They both allow polymorphism in a second dimension. In addition to inheritance, you now also have instantiation.
  • They both facilitate code reuse by allowing the programmer to write type-agnostic algorithms, while in most cases preserving the type-safety and performance of type-specific algorithms.
  • Templates are a compile-time mechanism, while Generics are instantiated at runtime. Along this vein, I like to think of Templates as compile-time macros on steroids. All the C++ compilers I'm aware of implement Templates entirely in the front-end, very similarly to how the preprocessor implements macros. Because of this templates can be used and abused in many ways that Generics can't.

I think most everybody will agree with me at this point. So the next major question is why did the CLR people decide to go with the 'limited' functionality of Generics instead of Templates? Well for starters, the CLR as a platform does not preclude C++ or any other language from incorporating Templates since that all happens at compile time and require no help from the CLR. Now granted there is no metadata to express templates that would make them cross-language, but as far as I know, there has never been any cross-language Templates.

John stated, "Generics seem to really answer the freshman CS collections problems while missing some of the more expressive power of C++ templates." I agree mostly with his statement. I disagree with the implied statement that Generics don't solve/answer the 'bigger real world problems that real programmers face'. First off we must remember from our CS theory classes that all computer languages are functionally equivalent. That is to say if you can do it in one of them, you can do it in all the others, but it might be significantly harder or require more work on the part of the programmer, but it is not impossible. So what are the real situations that real programmers face that Templates make easier but Generics don't (or at least not as easy)? I'm sure there are a few. The biggest one that springs to my mind is constants. I've written a few templates that take as a parameter the initial size or the size to grow. With Generics you're forced to use a readonly field to store such information. Not quite as elegant, but close enough for me until a performance test proves otherwise (in which case I'll probably look at changing algorithms first).

I personally would contend that being able to write type-agnostic collections and algorithms, that are still type-specific to the consumer really is the 90% case. Hence Generics that are really just trying to solve the freshman CS problem are solving most of the real problems. At least for now, I'm sure in a few years that will all change.

BTW John, you and I took many of the same freshman classes, and I don't remember any stuff about collections, type safety, templates or that sort of thing until at least my sophomore or junior year. Are there any colleges out there that teach that sort of stuff to first year CS students?

--Grant

Comments

  • Anonymous
    January 01, 2005
    Since a C++ Template is similar to a Code Generator, I guess that I'd prefer to use Templates, but I really hate the Template syntax.

    So, I just use ASP (or CodeSmith) to generate my strongly typed classes.
  • Anonymous
    January 02, 2005
    One of the problems that I see is that operator overloading is not accessable from within a generic algorithm, because operators are static methods, and can't be contained in an interface.

    So all those cool generic algorithms that could work on an int/float/ComplexNumber/RationalNumber are that much harder to implement.
  • Anonymous
    January 04, 2005
    Yes, even the language designers spent a fair amount of time trying to figure out a good clean way to do what they called static contracts. They compromised with themselves and came up with a single 'special' contract: the default constructor, which they hoped would cover the 90% case. Only time and custoemr feedback will tell if they chose correctky...
  • Anonymous
    January 12, 2005
    Perhaps I should have said "Generics are not as useful for the project I'm working on right now."

    I was trying to create functions that were "drop in" replaceable for the C# constants and operators. (We hope to then change operators on the fly to effect code mutation.) Due to the absence of a INumber interface or (for lack of a better term) "implicit" type constraints, I ended up with a common pattern in c++.

    A macro (called 9 times for 9 differen numeric types) calls a template, that does all the work, occasionally the template will be specialized by number type (using another set of macros.) These repetative macros (that really just declare the way the template might be called) are really what generic programming tries to prevent.

    I must conceed that this is not the 90% case, and C# did readily link to another language with rich templates and macros when I needed it.

    BTW I guess Dr. Burton's data structures was a sophmore level class. As his former grad student, I should be ashamed of myself.