Article Discussion
Generics in C#, Java, and C++
Summary: Anders Hejlsberg, the lead C# architect, talks with Bruce Eckel and Bill Venners about C# and Java generics, C++ templates, constraints, and the weak-strong typing dial.
20 posts on 2 pages.      
« Previous 1 2 Next »
The ability to add new comments in this discussion is temporarily disabled.
Most recent reply: December 13, 2007 5:12 AM by Michiel
jdnicolet
Posts: 6 / Nickname: jdnicolet / Registered: October 27, 2003 7:58 PM
Re: Generics in C#, Java, and C++
January 29, 2004 8:55 AM      
I would like to express some remarks and complements about the above article.

- I find the implementation strategy chosen by C# quite good, given the goal aimed at, i.e. basically a good way of defining strong typed containers (and other similar parameterized classes). The presented arguments sounds convincing, and show that the decisions were made on purpose. It reinforces my believing that "C# is Java done right".

- Some remarks about the comparison with C++. It's true that the mechanism is natively "blind" and gives cryptic error messages. But the mere fact that it gives an error message, however cryptic, is just the proof that it does indeed type check the generic parameters, hence doing strong typing.

- Although the constraint mechanism is not offered natively in the language, we have today excellent libraries (at least one: BOOST (www.boost.org)) allowing to do it, both with clearer error messages and with a granularity sufficient to allow any constraint checking, and this without requiring to some artificial factory just to be able to check for the presence of an arithmetic operator.

- I dislike comparing generics with macros, and thus in any programming language whatsoever. Macros are by definition lexical substitution patterns, while generics (or templates in the C++ case) are of a syntactic nature, thus they are acting at a higher level. This is why templates allow much more powerful constructs than macros, at least in C++. True, for offering just parameterized containers, macros would be sufficient. The former Tools.h++ library, a now antic fundamental library by Rogue Wave offered a full range of generic collections implemented with macros, more than ten years ago, when templates were not fully stabilized and widespread among C++ compilers. A little reflection shows that macros are sufficient to just insert an automatic cast in front of a generic (Object based) implementation.

- The whole purpose of templates in C++ is much, much broader. It goes today in the direction of so-called generative programming, where it is possible to design optimized classes tailored to specific choices made by the programmer when instantiating the template. The goal is to selectively construct a class by assembling tidbits of code and keeping only the necessary parts. In order to be efficient, this mechanism has to be performed at compile time, precisely to be able to suppress unnecessary code generation. Doing it with a run-time mechanism would be highly inefficient, from the memory footprint point of view. A classical example in this direction is the first achievement in the generative programming field, the computation of prime numbers at compile time. Computing a moderately large number may lead to the recursive instantiation of tens of thousands of templates that completely disappear afterwards (due to constant folding requirements imposed on the C++ compiler), leading to a vanishingly small amount of generated code, namely the sole computation result.

- The piecewise construction of a user-tailored class using generics needs some powerful support from the generic mechanism, among them at least the possibility of recursive substitution. This implies that a way must be offered to stop the recursion, and this is achieved in C++ by the so-called partial template specialization mechanism. Most programming languages supporting generics don't go that far, because this is roughly equivalent to integrate a substitution engine like Mathematica within the compiler, a knowingly complex task, explaining why the number of conforming compilers is still less than a dozen, after serveral years of standard's availability. By the way, the Microsoft C++ compiler, which has striking quality in the code optimization field, lags years behind the C++ standard, and is basically unusable to devise serious generative programming libraries.
Travis
Posts: 1 / Nickname: deuce / Registered: February 27, 2004 2:24 AM
Re: Generics in C#, Java, and C++
February 27, 2004 7:48 AM      
Likely a little late ... but, hopefully, someone's listening.

I'll just cut to the chase ...

It APPEARS that C# does not allow me to override the virtual default property of ArrayList in an attempt to return a specific type (ex. Fred). It also APPEARS that I can have no "indexed" property other than the default (but, I admit, I haven't looked into this thoroughly).

I was barely able to follow along with the discussion of "List<T>" ... I've tried various syntax in C# (as the MSDN doc does not necessarily, accurately, reflect the product) as well as MSDN searches. Based on the fonts used, I presumed it was actual C# syntax. Is this merely theoretical ... or vaporware ... or what? Regardless, aside from the early type-checking, I'm not sure that's what I want anyway.

I'm used to VB6 (keep the laughter down) and coding things like a Person class and a Persons class. Of course, I couldn't inherit Persons from Collection. So, I dragged around the same basic code everywhere and basically just changed the type of what was contained. I started doing the same thing in C# when I realized "hey, wait a minute, I can just inherit from ArrayList". But, that did me no good 'cause, MOSTLY, what I wanted (and this might seem stupid to a lot of you, but, I don't see why I'm not permitted to have it) is to have the default, or any, "indexed" property return the type I want (ex. Person). Of course, by simply overriding Add and Insert (not sure about constructors just yet), I could be relatively assured that only Person will be in the list (which is mostly what the article discussed), but, I'm more about un-cluttered, ridiculously readable, code. And, having a default "indexed" property which returns MY type AND, for that matter, having the Add and Insert methods also return the object typed as MY type (don't ask), helps me do that.

As it is, I've created the AL class which has a private member of ArrayList which it uses to perform all the same methods and properties of ArrayList ... with ONE exception (no, not that kind of exception) ... there is NO default property. As such, I can create a class (ex. Persons) inherited from AL and then simply ADD a default "indexed" property which returns the appropriate type (ex. Person).

Sorry for being so detailed ... more often than not, when I'm not, I'm simply misunderstood.

Just out of curiosity, can I, ever, overload the default property? I presume that, if I could've (presuming that a different return type is a change to the signature), that I wouldn't have noticed any problem when I tried removing "override" to my attempt to override, and, consequently, overload, the default property.

Thanks.
Mike
Posts: 1 / Nickname: kupci2 / Registered: March 2, 2005 8:49 AM
Re: Generics in C#, Java, and C++
January 13, 2006 8:18 AM      
> I would like to express some remarks and complements about
> the above article.
>

> - Some remarks about the comparison with C++. It's true

Good comments, your same points were also brought up on usenet:

http://groups.google.com/group/comp.lang.c++/browse_frm/thread/b51628e32c118fcf/cc6a04d7b14da66e?q=properties&rnum=5#cc6a04d7b14da66e
Kojo
Posts: 1 / Nickname: kojo / Registered: March 26, 2006 4:13 AM
Re: Generics in C#, Java, and C++
March 26, 2006 9:44 AM      

> Difference number two is C# does strong type checking when you
> compile the generic type. For an unconstrained type parameter,
> like List<T>, the only methods available on values of type T
> are those that are found on type Object, because those are the
> only methods we can generally guarantee will exist. So in C#
> generics, we guarantee that any operation you do on a type
> parameter will succeed.
>
> C++ is the opposite. In C++, you can do anything you damn well
> please on a variable of a type parameter type. But then once
> you instantiate it, it may not work, and you'll get some
> cryptic error messages.


This is actually somewhat misleading. In C++, instantiation happens at compile time, which means "anything you damn well please" is checked at compile time, not at runtime like the above quote suggests (IMO). So in C++ any template instantiation error messages are seen at compile time, which is way better than in C#.

Also, the fact that C++ template instantiation error messages are cryptic is mostly due to the compiler writers having to focus (IMO) on supporting templates to meet the Standard, rather than any limitation of the language. This is changing with each new compiler versions coming out.

It goes even further than this: in C++ you can only do on the template type parameter what the type parameter allows you to do, so it's actually safer than in C#. C++ enforces the full type's actual interface.

This is probably why C# has the concept of constraints and C++ doesn't: C++ doesn't need it (in some ways, it's already there), whereas they are needed in C# due to the weakness of having to go through Object when instantiating templates.
Michiel
Posts: 1 / Nickname: michiel / Registered: December 12, 2007 10:49 PM
Re: Generics in C#, Java, and C++
December 13, 2007 5:12 AM      
Great article!

However, I was a bit disappointed to learn that it is not possible to use operators (such as operator+) as a generic constraint. And indeed, since it is not possible to add static methods in a constraint, the natural consequence is that operators cannot be used as a constraint. You propose to use a Calculator<T> as a "man-in-the-middle" solution. I have a few questions about this:

- Why aren't static functions just allowed in interfaces?
- Is it not possible to use concepts such as proposed for the new C++ standard: special interfaces used to hold the constraints for a generic (including static functions)?
- Another solution: use "interface extensions" (in accordance to type extensions in 3.0): one could define an interface to an existing class or valuetype containing the functions you want to use as a constraint. Like this, you could define an interface extension, having the operator+ and adding it to the list of constraints of your generic.
- Isn't the overhead of having a wrapper class Calculator<T> giving C# the same disadvantage as the implementation of generics in Java? After all, in Java, int's are being boxed as you point out, but with a Calculator wrapper, as a developer I'm obliged to box my int as well, just to overcome a problem that could be easily tackled with syntactic sugar. Where am I missing something?

Nevertheless, I like C# a lot (almost as much as C++). Keep up the good work.
20 posts on 2 pages.
« Previous 1 2 Next »