Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Generics in C#, Java, and C++

20 views
Skip to first unread message

atgr...@gmail.com

unread,
Jan 1, 2006, 6:08:09 PM1/1/06
to
Here is the "lead C# architect" attempting to impugn C++ templates
(bottom of the page).

http://www.artima.com/intv/generics2.html (bottom of the page)
(Full article begins at http://www.artima.com/intv/generics.html)

I think every employee at Micrsoft must be required to take a class in
"FUD marketing" before speaking with anyone outside the company. I
think the term "money oriented programming" is suitable here.

Luke Meyers

unread,
Jan 1, 2006, 10:46:57 PM1/1/06
to
Wow, that's truly appalling. It's a shame that a programming language
can't sue for libel.

Luke

Greg

unread,
Jan 2, 2006, 12:07:24 AM1/2/06
to

Um, the interview seems neither inaccurate nor the least bit derogatory
toward C++; so it's hard to see how C++ the language is being
"impugned."

Templates in C++ can often replace C macros (look at std::min and
std::max). But of course doing so would only make sense if templates
were better than macros, which of course, they are.

Greg

Luke Meyers

unread,
Jan 2, 2006, 3:58:44 AM1/2/06
to
Greg wrote:
> Um, the interview seems neither inaccurate nor the least bit derogatory
> toward C++; so it's hard to see how C++ the language is being
> "impugned."

Okay, I'll go into more detail.

> Templates in C++ can often replace C macros (look at std::min and
> std::max). But of course doing so would only make sense if templates
> were better than macros, which of course, they are.

Right, that's exactly the point. Templates are vastly more expressive
and useful than macros, so when the article states:

"C++ templates are really just like macros, except they look like
classes."

it's simply untrue. Shortly thereafter, he apparently contradicts
himself:

(1) "C# does the instantiation at runtime"
(2) "C# does strong type checking when you compile the generic type"

He's referring here to class instantiation, not object instantiation.
I don't see how you can claim to do strong type checking without
instantiating the generic. Maybe some parts of it are left for run
time, but his whole context here is about type-checking, so that's the
only part that's really relevant.

Anyway, he uses this as a basis for pointing out that, due to this
strong type checking at compile time, only valid operations for that
type are available at runtime. Well, yes, obviously -- otherwise, it
would fail the compile-time type checking. So again, I don't see how
he can claim that this is runtime instantiation. Maybe he's confusing
polymorphism with template instantiation or something?

He then goes on to use different wording to describe the fact that C++
also does strong type checking at compile time, but somehow decides
that the two languages are completely opposite in this regard:

"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... So in a sense, C++
templates are actually untyped, or loosely typed. Whereas C# generics
are strongly typed."

It's a valid criticism that C++ template error messages are sometimes
verbose and difficult, but that's a red herring (besides, how do C#
error messages compare in similarly complex cases?). Both C++ and C#
provide compile-time type-checking of templates. If there is an error,
the compiler will report it. What he's doing here is interpreting this
behavior completely differently in each case. For C#, all he does is
talk up the wonderful guarantees provided by this checking, completely
glossing over the fact that, of course, C# must also generate error
messages if the type checking fails. For C++, he interprets the exact
same behavior as a failure, a complete lack of a type system. The
error messages are EXACTLY how you get strong type-checking! It's the
earliest possible opportunity, short of IDE integration, to check that
the operations performed on a parameterized type are valid. The
compiler will not let you proceed if you have type errors in your code
-- that IS strong type checking! His lack of understanding of the
terms he's using is further indicated by the phrase "in a sense" -- did
the definition of "strongly typed" suddenly become subjective? It's
the same as the obviously deceptive "from a certain point of view" sort
of reasoning.

It's absurd, it's false, it's misinformed, it's FUD. Engage your brain
and read it until you realize this.

Luke

Mirek Fidler

unread,
Jan 2, 2006, 7:33:47 AM1/2/06
to
Well, I guess that something really stinks there:

"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,"

"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. For
example, if you have a type parameter T, and variables x and y of type
T, and you say x + y, well you had better have an operator+ defined for
+ of two Ts, or you'll get some cryptic error message.

Actually, for me it looks like "the opposite". C# seems to do no strong
type checking (because the only type allowed in template code is
Object, that is equivalent of "void *"), whereas C++ does it (beacause
compiler emits "cryptic" error messages for invalid operations at the
runtime).

I guess somebody should explain to C# inventor what is strong type
checking :)

Mirek

Mirek Fidler

unread,
Jan 2, 2006, 7:34:46 AM1/2/06
to

> compiler emits "cryptic" error messages for invalid operations at the
> runtime).

*compile time*

Sorry :)

Mirek

Mirek Fidler

unread,
Jan 2, 2006, 7:44:03 AM1/2/06
to
> error messages compare in similarly complex cases?). Both C++ and C#
> provide compile-time type-checking of templates.

Actually, from what I have read, C# seems to provide "void *" level of
checking... (of course, with GC langauge, void * is more useful and
Object prehaps has more useful properties than void *, but in the end,
it is just this...)

Mirek

atgr...@gmail.com

unread,
Jan 2, 2006, 11:09:28 AM1/2/06
to
Very well said, Luke!

You got most of it, but you left out this part:

"C# generics are really just like classes, except they have a type
parameter. C++ templates are really just like macros, except they look
like classes."

He "forgets" to point out here that C# generics are much more limited
than C++ templates. C++ templates aren't just limited to classes, and
C++ template parameters aren't limited to typenames.

Just like in Java, C# generics are just a way to provide another bullet
point for the language feature set. I wonder if the "lead C#
architect" actually thought he could improve on C++ templates (if that
could have been done, wouldn't the C++ committee have done it?), or if
he just didn't realize why generic programming is important:

"It is silly to abstract an algorithm in such a way that when you
instantiate it back it becomes inefficient." - Alex Stepanov

Aaron

Luke Meyers

unread,
Jan 2, 2006, 1:32:02 PM1/2/06
to
> "It is silly to abstract an algorithm in such a way that when you
> instantiate it back it becomes inefficient."

Hey, computers keep getting faster! We don't need to code efficiently
anymore.

At least, so sayeth the bloaters of code, the havers of sweetheart
backroom deals with the hardware vendors.

Cheers.

Luke

P.S. Generics ain't templates, but when I'm stuck writing Java I'm
happier having them than not. As for C#... I don't put myself in that
position.
P.P.S. Can we start pronouncing it "See-octothorpe?"

Greg

unread,
Jan 2, 2006, 4:59:54 PM1/2/06
to

No, C# does perform type-checking for generics since it ensures that
the parameterized type specfied is compatible with the declared type,
in this case, the Object type. In other words, void * would not be
accepted as a parameter type for C#'s List<> generic while it would be
accepted for C++'s std::list class template.

And in fact there is no language supported way to prevent C++'s
std::list<> (or any template) from being instantiated with void * or
any other type. C++ simply performs no type checking on the type
parameter for a class template, so it accepts any type. That is not to
say that a template can be successfully instantiated with any type. But
if there is an error instantiating a template with a particular type,
it is not often clear whether the template or the parameterized type is
to blame.

Lack of parameterized type checking is not necessarily a shortcoming of
C++. Nor is it an argument that C++ should perform such checking
(though there are proposals to add such support to the language).
Instead it is simply an inarguable, factual observation that C++ does
not support this concept.

Greg

Luke Meyers

unread,
Jan 2, 2006, 10:58:23 PM1/2/06
to
Greg wrote:
> And in fact there is no language supported way to prevent C++'s
> std::list<> (or any template) from being instantiated with void * or
> any other type. C++ simply performs no type checking on the type
> parameter for a class template, so it accepts any type. That is not to
> say that a template can be successfully instantiated with any type. But
> if there is an error instantiating a template with a particular type,
> it is not often clear whether the template or the parameterized type is
> to blame.
>
> Lack of parameterized type checking is not necessarily a shortcoming of
> C++. Nor is it an argument that C++ should perform such checking
> (though there are proposals to add such support to the language).
> Instead it is simply an inarguable, factual observation that C++ does
> not support this concept.

Actually, there are multiple ways to accomplish this. You can't mess
with std::list, but for your own templates, you have options. If you
want explicitly specify the types allowed for a template, you can use
partial template specialization on one or more common base classes. If
you want to simply exclude certain types, I'd use BOOST_STATIC_ASSERT
or a similar construct to check against them.

Luke

Mirek Fidler

unread,
Jan 3, 2006, 3:10:01 PM1/3/06
to
>>Actually, for me it looks like "the opposite". C# seems to do no strong
>>type checking (because the only type allowed in template code is
>>Object, that is equivalent of "void *"), whereas C++ does it (beacause
>>compiler emits "cryptic" error messages for invalid operations at the
>>runtime).
>
>
> No, C# does perform type-checking for generics since it ensures that
> the parameterized type specfied is compatible with the declared type,
> in this case, the Object type. In other words, void * would not be
> accepted as a parameter type for C#'s List<> generic while it would be
> accepted for C++'s std::list class template.

That is not what I wanted to say.

The thing is that C# (if I understand things well) allows only Object's
methods to be called in templated code. That it turn makes is quite
limited for expressing generic algorithm. It is somewhat similar to
using "void *" for implementic generics (like that old qsort function of C).

As long as only Object is supported, the only possible way how to make
more complicated stuff is casting - and that is hardly "strong type
checking", it is more "void *" kind of things in compile time.

But then again, I might misundestand the issue. This is what I got from
the article.

Mirek

nik...@microsoft.com

unread,
Jan 3, 2006, 4:35:28 PM1/3/06
to
Mirek Fidler wrote:
> >>Actually, for me it looks like "the opposite". C# seems to do no strong
> >>type checking (because the only type allowed in template code is
> >>Object, that is equivalent of "void *"), whereas C++ does it (beacause
> >>compiler emits "cryptic" error messages for invalid operations at the
> >>runtime).
> >
> >
> > No, C# does perform type-checking for generics since it ensures that
> > the parameterized type specfied is compatible with the declared type,
> > in this case, the Object type. In other words, void * would not be
> > accepted as a parameter type for C#'s List<> generic while it would be
> > accepted for C++'s std::list class template.
>
> That is not what I wanted to say.
>
> The thing is that C# (if I understand things well) allows only Object's
> methods to be called in templated code. That it turn makes is quite
> limited for expressing generic algorithm. It is somewhat similar to
> using "void *" for implementic generics (like that old qsort function of C).

Not true. You can specify a constraint for a template parameter. An
example from the C# language specification is:

public class Dictionary<K,V> where K: IComparable
{
public void Add(K key, V value)
{
...
if (key.CompareTo(x) < 0) {...}
...
}
}

Becuase of the constraint, we do know something more about K than
merely that it is an Object. We know it implements IComparable. The
compiler/runtime can therefore validate the call to CompareTo when
the template is compiled -- i.e., before it is instantiated.

> As long as only Object is supported, the only possible way how to make
> more complicated stuff is casting - and that is hardly "strong type
> checking", it is more "void *" kind of things in compile time.

The piece you're missing is how strong type checking interacts with
constraints.

Shezan Baig

unread,
Jan 3, 2006, 7:41:15 PM1/3/06
to
Greg wrote:
> Lack of parameterized type checking is not necessarily a shortcoming of
> C++. Nor is it an argument that C++ should perform such checking
> (though there are proposals to add such support to the language).
> Instead it is simply an inarguable, factual observation that C++ does
> not support this concept.


This is simply not true. In fact, I would go as far as saying that C++
supports this concept and much more!

In C++, I can assert (at compile time) not only whether a type T
derives from a particular class, but I can also assert all kinds of
other meta-information (e.g, whether type T is a pointer, is a
polymorphic type, is a function, is a fundamental type, etc etc)... the
list goes on and on...

I find the constraints in C# far too limiting. That's probably a
result of hardcoding these concepts into the compiler, rather than
allowing library developers to implement these concepts within library
code.

-shez-

Shezan Baig

unread,
Jan 3, 2006, 8:49:16 PM1/3/06
to
atgr...@gmail.com wrote:
> I wonder if the "lead C#
> architect" actually thought he could improve on C++ templates (if that
> could have been done, wouldn't the C++ committee have done it?)


Well, the C++ committee *is* improving on it. I personally cannot wait
for Stroustrup's idea of 'concepts'. Being able to specialize a
template based on a concept is just sweet :) Also, the 'auto' type is
a *big* improvement.

-shez-

Shezan Baig

unread,
Jan 3, 2006, 10:33:40 PM1/3/06
to
nik...@microsoft.com wrote:
> You can specify a constraint for a template parameter. An
> example from the C# language specification is:
>
> public class Dictionary<K,V> where K: IComparable
> {
> public void Add(K key, V value)
> {
> ...
> if (key.CompareTo(x) < 0) {...}
> ...
> }
> }
>
> Becuase of the constraint, we do know something more about K than
> merely that it is an Object. We know it implements IComparable. The
> compiler/runtime can therefore validate the call to CompareTo when
> the template is compiled -- i.e., before it is instantiated.

That is interesting. But it still seems to me that without these
constraints, we are losing some level of type-safety by making 'K' and
'V' simply 'Object's. For instance, consider this (rather inefficient)
implementation of a 'Dictionary':


public class Dictionary<K,V>
{
private List<K> keys;
private List<V> values;

public void Add(K key, V value)
{

keys.Add(value);
values.Add(key);
}
}


If 'Dictionary' is instantiated with different types for 'K' and 'V',
then there is obviously a type-mismatch in the 'Add' function. But
within the scope of 'Dictionary', the types 'K' and 'V' are just
'Object's. So, I would guess that 'keys' and 'values' are both of type
'List<Object>' (please correct me if I'm wrong, I'm just inferring this
based on the article).

So what I want to know is: how does the compiler know that it should
generate a type-mismatch error if 'Dictionary' is instantiated with
different 'K' and 'V' types? Does it just do a lexical comparison of
the type names?

If a lexical comparison is used to differentiate them, then how do we
handle the cases where we *do* want to behave a certain way if we
detect whether they are the same type? (we are drifting slightly off
the 'Dictionary' example here, but there are times where we want to
specialize behaviour based on certain type traits). We could probably
use reflection, but if we did that, then we might as well not use
generics since we completely lose *all* compile-time type safety.

Granted, this is a very simple, silly example - but real code would
probably be more complicated. The point is this: In a reasonably sized
generic component, it would be dangerous to lose type information, even
within the scope of the generic class.

-shez-

nik...@microsoft.com

unread,
Jan 9, 2006, 3:10:30 PM1/9/06
to
Shezan Baig wrote:
> nik...@microsoft.com wrote:
> > You can specify a constraint for a template parameter. An
> > example from the C# language specification is:
> >
> > public class Dictionary<K,V> where K: IComparable
> > {
> > public void Add(K key, V value)
> > {
> > ...
> > if (key.CompareTo(x) < 0) {...}
> > ...
> > }
> > }
> >
> > Becuase of the constraint, we do know something more about K than
> > merely that it is an Object. We know it implements IComparable. The
> > compiler/runtime can therefore validate the call to CompareTo when
> > the template is compiled -- i.e., before it is instantiated.
>
> That is interesting. But it still seems to me that without these
> constraints, we are losing some level of type-safety by making 'K' and
> 'V' simply 'Object's.

Not at all, because if you don't specify any constraints it doesn't
mean "anything goes"; on the contrary, it means you're rather limited
in what you can do with objects of type 'K' and 'V'.

> For instance, consider this (rather inefficient)
> implementation of a 'Dictionary':
>
>
> public class Dictionary<K,V>
> {
> private List<K> keys;
> private List<V> values;
>
> public void Add(K key, V value)
> {
> keys.Add(value);

This should be a compile-time error. The keys field is a List<K>
so its Add method takes a single parameter of type K. Since value
has type V, the compiler should ask itself, "can I prove that type
V is convertable to type K?" The answer is no since you specified
no constraints on either type.

If you wanted to specifically allow this case you would specify
the constraint "where V : K".

> values.Add(key);

Same as above in reverse.

> If 'Dictionary' is instantiated with different types for 'K' and 'V',
> then there is obviously a type-mismatch in the 'Add' function. But
> within the scope of 'Dictionary', the types 'K' and 'V' are just
> 'Object's. So, I would guess that 'keys' and 'values' are both of type
> 'List<Object>' (please correct me if I'm wrong, I'm just inferring this
> based on the article).

No, keys and values have types List<K> and List<V>. In the absence of
constraints, the compiler doesn't know very much about type 'K', but it
still has an identity; thus the 'K' in List<K> denotes the same type
as the 'K' in the first parameter to the Add method above.

You might find the following paper interesting, "The Design and
Implementation of Generics for the .NET Common Language Runtime":

http://research.microsoft.com/projects/clrgen/generics.pdf

Shezan Baig

unread,
Jan 9, 2006, 3:41:02 PM1/9/06
to
nik...@microsoft.com wrote:
> You might find the following paper interesting, "The Design and
> Implementation of Generics for the .NET Common Language Runtime":
>
> http://research.microsoft.com/projects/clrgen/generics.pdf


Thanks for the link :)

-shez-

0 new messages