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