Linked by Rüdiger Klaehn on Thu 5th Aug 2004 05:00 UTC
.NET (dotGNU too) One of the most awaited features of Microsoft .NET 2.0 is generics. Generics promise to increase type safety, improve performance, reduce code duplication and eliminate unnessecary casts. The most obvious application of generics in the framework class library are the generic collections in the new System.Collections.Generic namespace. Much has been written about those, but they are not the topic of this article.
Order by: Score:
Interesting.
by Miguel de Icaza on Thu 5th Aug 2004 05:25 UTC

I like your proposal for IArithmetic as a type constraint.

Generic performance
by Jacques on Thu 5th Aug 2004 05:31 UTC

Would it be possible to write, say, a generic sorting function without having the primitives implicitly boxed? This can't be done with java generics, and it's a real shame (and pain) (in java it's even worse, there's no operator overloading.)

RE: The Problem with .NET Generics
by jeff on Thu 5th Aug 2004 05:54 UTC

@Rüdiger Klaehn
Have you posted this on the suggestions (feature request) area of MSDN? I believe the site is http://lab.msdn.microsoft.com/productfeedback/ They seem to be taking and responding very well to suggestions with all upcomming development products including the .NET framework. I've already added two suggestions, one of which I think will be implemented in C# 2.0 or the next release version. If you haven't I would go over there right away and get it in.

As far as Method Constraints, I believe these very features you speak of are mentioned in the C# 2.0 specs however I can't recall if operator constraints are allowed.

Thanks for the insight.

v What's that?
by QuantumG on Thu 5th Aug 2004 06:07 UTC
Nice catch. What will Mono do?
by Doug Dew on Thu 5th Aug 2004 06:11 UTC

Nice catch. Thanks for the nice writeup.

Hopefully Anders and Co. will address this deficiency before they ship C# 2.0 final.

But if they don't, then what will the Mono guys do? Fix this "bug" by adding something like the IArithmetic interface even though .NET doesn't have such a fix? Or leave something broken just because Microsoft's implementation is broken? In a way, this could prove to be an interesting test of the relationship between Mono and .NET.

Another way
by leppie on Thu 5th Aug 2004 06:13 UTC

Nothing stops you from using reflection and checking your generic type in the constructor, albeit a bit slow, but an implementation (hashtable) could be easily used to cache entries.

We dont want C# to become the syntactic mess C++ has become. Many people prefer C# for exactly this reason!

The problem with IArithmetic
by Stefan Farthofer on Thu 5th Aug 2004 06:30 UTC

You point out, that writing a wrapper class would be to slow, which is true. But adding the IArithmetic interface would only relieve you of the work of writing those wrapper classes, performance wise.

Even if the numbers will not be stored as objects but as real int and float fields, the generic code still has to call the Add method instead of just issuing the ADD IL opcode. In the end, this might save you a little space since just an int needs to stored, but the unnecessary function call remains.

Great article
by Yamin on Thu 5th Aug 2004 06:46 UTC

What a great article. It walked you through solving the problem using current means. that showed why it was a problem. then it went on to propose many solution. Finally, it came out with a very reasonable solution and demonstrated its reasonableness.

We need more like this one.

Maybe a reason?
by Eric on Thu 5th Aug 2004 07:02 UTC

After reading this article I realized that it was somewhat over my head as I am primarily a web developer that doesn't have such issues much of the time. With that said, C# and .NET is supposed to work not only with different languages but also with different purposes (ie web applications). Maybe then the reason that something like your IArithmetic<T> (which I really have no understanding of whatsoever ;) could have been left out because other languages such as C++ or C are available for performing more mathmatical type opperations. This is just a thought, and from what I understand, I do agree what you are talking about makes tons of sense. Good Article!

What is generic
by Woot on Thu 5th Aug 2004 07:37 UTC

Can anyone please explain what generic is when it comes to programming ?

re: The problem with IArithmetic
by PG on Thu 5th Aug 2004 08:16 UTC

The way I understood it, not having to automatically box primitives was seen as the main advantage C# generics has over Java generics. Why would you want to throw away that advantage? Making primitives implement IArithmatic would mean you throw away primitives and make them all objects.

re: The problem with IArithmetic
by andy on Thu 5th Aug 2004 08:39 UTC

Making primitives implement IArithmatic would mean you throw away primitives and make them all objects.

They'd only be boxed when you refer to them through an IArithmetic variable. In the same way that they aren't boxed just because they implement IComparable.

Besides, as far as I understand it the Microsoft runtime creates specialised instances of generic classes when the type parameter is a primitive type. In the example in the article, Point<int>, Point<float> and Point<double> would each be specialised for their respective parameter types, so that no IComparable boxing would be necessary.

That's obviously a size-speed tradeoff.

Credibility destroyed
by Chris on Thu 5th Aug 2004 09:18 UTC

C++ templates are a compile-time feature much like a macro preprocessor and are thus not a good solution for a highly dynamic language such as C#.

Eugenia: wild inaccuracies do not enhance the site's reputation. Nor does this nonsense generate any interest in C#.

Re: Credibility destroyed
by myzz on Thu 5th Aug 2004 10:30 UTC

Only thing that is wrong with this sentence, is that I wouldn't call C# as a highly dynamic (although it's more dynamic than C++).

Re: Credibility destroyed
by Zab Ert on Thu 5th Aug 2004 10:48 UTC

No, Chris is right. C# isn't even more dynamic than C++. Maybe the libraries are. I have complained five times about the quality of the articles, to Eugenia, just like him. And every time I'm "moderated away." I really like this site and I really don't want it to become yet another /.

Re: Credibility destroyed
by myzz on Thu 5th Aug 2004 11:44 UTC

C# has some reflection support (unlike C++), which can be considered as dynamic feature.

Re: Credibility destroyed
by jeff on Thu 5th Aug 2004 12:26 UTC

Last I can remember there are a few definitions of the word dynamic. I took dynamic to mean run-time oriented if that makes sense. In other words when the word dynamic is used it can mean that something is happening at runtime. In this situations what could that be... oh yeah generic type substitutions. Just because the user of a langauge isn't in control of dynamic features of a langauge doesn't make them non dynamic. It is simply a different definition of the word dynamic which is used more regularly and maybe only recently so to mean langauge features that alow program constructs to by highly configureable by the user or the program itself (ex. code changes or runtime).

RE: @myzz
by renoX on Thu 5th Aug 2004 12:28 UTC

Unless I'm mistaking RTTI in C++ is reflection, no?

And it is a dynamic feature..

The biggest problem with RTTI in C++ is that it took a long time to be available so it is still not widely used..

But a new project starting now could probably count on the availability of RTTI..

Implicit Interfaces
by Rich on Thu 5th Aug 2004 13:03 UTC

I came up with a similar implicit interface idea a couple of years ago, but mine didn't involve any extra syntax (i.e. more like C++). The compiler knows about the requirements of the parameter types for a generic type when it compiles the generic type, so it could compile in an implicit interface without the developer ever having to know about it. For generic classes that can get by with just System.Object operations, no interface would be required. For those requiring just the basic numeric operations, the compiler would compile a special-case generic class for the arithmetic types (polymorphic IL opcodes mean just one should be required) and a separate case generic with an implicit interface having the required overloaded operators. The compiler, upon compiling the instantation of a generic type, knows exactly what the capabilities of the parameter type are, just as in C++ and in the current C# generics, so ensuring the match against the required interface should be no problem, just as it is now for explicit constraints. Because the parameter type may be used in the generic instantiatiation separately from its definition (i.e. separate assembly), regular interface specification won't always be possible. There are a number of solutions which don't require engine modification, such as using wrapper classes, delegates, and reflection.emit.

The best solution, IMO, however, is to extend IL so that the instantating assembly can specify that the parameter type implements the implicit interface, and to modify the engine so that it can perform the interface mapping after the initial loading of the type. The engine already has to be able to generate vtables for interface-implementing classes which hook up method bodies to interface methods; it just needs to be made flexible enough to perform the mapping on demand rather than just at its initial type loading. This on-demand approach would also work well for purely dynamic types, both as generics and their parameters, and would incur no excessive overhead as would be required by purely compiler-based approaches. Perhaps I'm overlooking something, though; if so, please let me know.


Rich

RE: Implicit Interfaces
by Rich on Thu 5th Aug 2004 13:10 UTC

I noticed I made a mistake: polymorphic IL opcodes wouldn't eliminate the need for special cases for each of the primitive types, since they must also be stored as their concrete unboxed types (otherwise boxing overhead becomes a problem).


Rich

Reflection
by Zab Ert on Thu 5th Aug 2004 13:11 UTC

Yes, you are right, jeff, /current/ RTTI is *not* as complete reflection system as the .net/java reflection (altough XTI is).
But this fact does not change the fact that we are seeing many weak articles being published here at OSNews, as the current one.
There is a series of flaws in the current article: not very-well researched (restricted generics where thoroughly studied to inclusion in c++ during the last ISO std round), weak/incorrect comparisons with c++, boxing/unboxing not mentioned/considered.
OSNews used to be more strict/edited (editorialized?); altough Eugenia is _not_ completely unbiased, her articles are usually very good. But the other articles that are entering are deserving some questioning/polishing/removal of factual errors and flamebaits. IMHO.
Obviously, Eugenia can say to me: Zab, if you are not liking, leave. I'll be hurt, but it's ok.

RE: Implicit Interfaces
by jeff on Thu 5th Aug 2004 13:13 UTC

Once again, please submit this to the microsoft feedback site I listed above. If not this release, maybe the next?

RE: Implicit Interfaces
by jeff on Thu 5th Aug 2004 13:18 UTC

@Zab Ert

Got ya. I've noticed this site leaning a little tword particular technologies. Maybe people need to submit more news on the underdogs. And maybe Linux isn't as much of an underdog anymore.

I really enjoy technical articles like this one the most. With that said, I think a seperate site that is more software technology oriented more than OS oriented may be a better place for such articles. Maybe OS news should be seperated into a few different new portals? I would end up going to them all most likely.

Re: Credibility destroyed
by Rich on Thu 5th Aug 2004 13:24 UTC

C++ templates _are_ just glorified macros; there's nothing special about them at runtime. C# is certainly more dynamic than C++, unless, of course, C++ has obtained the ability to portably generate classes at runtime and I just didn't get the memo. Also, the core parts of the IL library, including its reflection capabilities, are a part of the C# language specification; you can't separate C# from those parts of the library and still call it C#.


Rich

RE: Credibility destroyed
by Andreas Huber on Thu 5th Aug 2004 13:32 UTC

C++ templates are a compile-time feature much like a macro preprocessor and are thus not a good solution for a highly dynamic language such as C#.

C# is a multi-purpose language, parts of it are static (e.g. normal method calls are resolved at compile time) and parts of it are dynamic (e.g. with Reflection you can call any method on an object without knowing the objects' class).
This is a good thing because most of the time you are fine with static behavior and can thus benefit of compile time verification and good performance. Sometimes tough you need the dynamic behavior and are willing to deal with more errors at runtime and are also willing to sacrifice performance. Therefore, I absolutely don't see why generics should not be suitable for C#. It allows you to uncover more bugs at compile-time and improves performance in a lot of areas.

Eugenia: wild inaccuracies do not enhance the site's reputation. Nor does this nonsense generate any interest in C#.

If you accuse someone of producing wild inaccuracies you should definitely say what exactly those inaccuracies are and why you think so.

Regards,

Andreas

MS Feedback
by Rich on Thu 5th Aug 2004 13:34 UTC

Jeff, I just checked the link you provided and it requires a passport account which I have no intention of getting. If you want to submit my idea, go ahead.


Rich

RE: Reflection
by Andreas Huber on Thu 5th Aug 2004 14:13 UTC

There is a series of flaws in the current article: not very-well researched (restricted generics where thoroughly studied to inclusion in c++ during the last ISO std round)

So? As the author says in the article, he wants to explore why .NET generics are not suitable for numerical programming. Mentioning what you suggest seems highly off-topic.

weak/incorrect comparisons with c++

What exactly are the weak/incorrect comparisons?

boxing/unboxing not mentioned/considered.

Why should he mention boxing/unboxing? Again, the article is about a problem of .NET generics and not about their benefits.

Regards,

Andreas

real dynamic languages or more strict ones?
by fuser on Thu 5th Aug 2004 15:58 UTC

This was an interesting article. Btw, considering that you defined C# as a dynamic language (and surely it's more dynamic than C++) it would be reasonable do what programmers in dynamic languages would do: use reflection to check if such method exist. this would happen at runtime, so the stati crew may disagree. Or you could do like Nice does : allow a developer to declare interfaces and to say that some classes implements them after the class has been created, like:

class Foo {...}
interface Ifoo{...}

class Foo implements Ifoo {}

Let me see if I get this right...
by Anonymous Coward on Thu 5th Aug 2004 16:37 UTC

You're complaining that you can't limit your template based on the availability of arithmetic operators.

So, did you try to compile your generic example above (Point<T>) using an object where the + operator would not apply?

All of the base primitives would work fine in your example.

However, if I read the spec correctly, as soon as you try create a struct/class that doesn't support + (we'll call it "Foo"), and try to declare it ("Point<Foo> f;") and use it ("f=f+f;"), you should get a compile-time error.

I cannot believe...
by Shapeshifter V.90 on Thu 5th Aug 2004 16:52 UTC

...you went on to ramble about the problem with .NET generics and completely left out of the issue of generics not being CLS compliant yet.

Eiffel generics?
by Miron Brezuleanu on Thu 5th Aug 2004 17:02 UTC

What about the Eiffel way?

They do stuff like:

class interface HASHED_SET[E->HASHABLE]
-- etc.
end

meaning that HASHED_SET is generic over E, and E has to inherit from HASHABLE. This is the simplest/cleanest syntax for constrained genericity I have encountered.

Eh?
by Rayiner Hashem on Thu 5th Aug 2004 17:08 UTC

This is a bit of a weird statement: "much like a macro preprocessor and are thus not a good solution for a highly dynamic language such as C#."

Macros are orthogonal to the dynamic properties of a language. Currently, the languages that have the most evolved macro systems (Lisp, Scheme), are also among the most dynamic languages available.

@Rayiner Hashem RE: Eh?
by PlatformAgnostic on Thu 5th Aug 2004 17:16 UTC

Macros in C++/C are quite different from Lisp Macros, wouldn't you say? From toying around with lisp, I've come to understand that lisp macros are actually pieces of logic while C macros are just text-substitution commands.

RE: Generic performance
by Andreas Huber on Thu 5th Aug 2004 17:28 UTC

Would it be possible to write, say, a generic sorting function without having the primitives implicitly boxed

Yes. One of the reasons why generics were introduced is that they allow you to write much better performing code. .NET 1.1 sorting can be up to 5x slower than C++ sorting. .NET 2.0 is only roughly 2x slower.

Regards,

Andreas

Glorified macros?
by Scott S on Thu 5th Aug 2004 17:55 UTC

Rich: You and I may have different ideas of what "glorified macros" means. C++ templates do more than just plop code in place; at compile time, the compiler can figure out a lot through templates about what class to generate. Specialized templates are an example of this. The template system is actually turing complete; I've seen it used to solve problems. The current C/C++ User's Journal also has an interesting article about using templates for loop unrolling.

Re: Credibility destroyed
by Stefan on Thu 5th Aug 2004 18:04 UTC

I also fail to see how C++ could be considered as dynamic as C# or Java (I'm a java guy so I'll stick with it in this discussion). To me dynamic means e.g. initializing a class where only a name is known, inspecting objects. I see some cumbersome workarounds (shared libraries are kind of) but for the runtime analysis and dynamic invocation of arbitrary objects I don't see any simple approach in C++. [If your point is that everything can be implemented in assembler that can be implemented in any other language then I'm fine with that argument, but certainly calling assembler object oriented or the like would make you appear a bit strange...]

How would you describe templates briefly? I think Eugenia's sentence has some valid points: Template instantiation happens at compile time (in contrast to c#). Instances of templates do not share a common type (whereas java generic types have more relation [wilcard operator]).

Re: Credibility destroyed
by Scott S on Thu 5th Aug 2004 19:04 UTC

Stefan: Briefly, templates are a mechanism to allow generic programming. They allow C++ functions and classes to be type-agnostic, and to be so effeciently.

I agree that Java and C# are more "dynamic" than C++, because they both have a run time environment, whereas C++ does not. C++ has different design goals than Java and C#, so I don't consider that a problem.

I wouldn't use Java's generics as a useful standard. As of 1.5, Java's support for templates/generics really only saves some typing. A Java generic always uses Object as the templatized type, and inserts the approrpriate castings so that the code is type safe. And that's the reason why different instantations of a Java generic can be related to each other: they're trivially related because they all use Object. C++ (and C#) generate actual classes with that type explicity in place.

@Stefan
by Zab Ert on Thu 5th Aug 2004 19:06 UTC

* initializing a class dynamically: COM and sons, CORBA and sons, etc...
* runtime analysis and dynamic invocation: XTI
* template instantiation, yes, occurs at compile-time (so they are absolutely typesafe).
* instances template types CAN share common "root" type, if you need (generally you don't).

@PlatformAgnostic
by Rayiner Hashem on Thu 5th Aug 2004 20:19 UTC

Yes, Lisp macros are vastly more powerful than C++ macros + templates, but in the end, both are mechanisms that allow changing of program behavior at compile-time. Meanwhile, "dynamism" allows changing of program behavior at runtime. The two mechanisms have nothing to do with each other --- you can have fully static languages with a macro processor (Ocaml with Ocaml4P), fully dynamic languages with no macro processor (Smalltalk), or fully dynamic languages with a macro processor (Lisp). That's really why I think the author's statement was weird --- templates being compile-time macros have nothing to do with the dynamism of the underlying language.

Simple Question
by logicnazi on Thu 5th Aug 2004 20:21 UTC

Why can't we implement the solution using wrapper classes integrated into the language definition (I think this is essentially what the article suggests) and then count on compiler optimizations to deal with the speed issue. This way the language/standards would require the least amount of change but compilers could choose to still implement these interfaces with just a simple + opcode?

I'm probably missing someone but am wondering what it is. Basically it seems like we only need a simple check to see it it is one of the primitive + operations and if it is just pretend all the interface stuff used isn't there.

@Zab Ert
by Rayiner Hashem on Thu 5th Aug 2004 20:26 UTC

* initializing a class dynamically: COM and sons, CORBA and sons, etc...
Both of which require extra-lingual functionality. If used with IDL (as both usually are), both are "grafted on," introducing their own types, own declaration syntax, specialized compilers (IDL compilers), etc. C++ does not allow you to load a class dynamically any more than asm does. It *can* be done in both, but it's not realistic to say-so because it requires significant support outside the language itself.

* runtime analysis and dynamic invocation: XTI
XTI doesn't exist in any usable form, yet. Maybe it'll be in C++ 0x, but it'll be 2010 at least before that get's widespread compiler support.

* template instantiation, yes, occurs at compile-time (so they are absolutely typesafe).
Type-safe templates in C++ are like airbags in a rocket.

@logicnazi
by Rayiner Hashem on Thu 5th Aug 2004 20:35 UTC

Yes, that would work. Essentially, what you'd be doing is getting rid of primitive types entirely and making everything be an object of a class. In practice, compiler technology is good enough at inferring the type of variables that they can usually eliminate the "object" overhead.

C# generics and C++ templates
by andy on Fri 6th Aug 2004 09:02 UTC

The dynamic vs. static discussion is beside the point.

From a programmer's perspective, generic classes in C# are instantiated and type-checked at compile-time, as are C++'s template classes. (How compiler and run-time system implement them is another matter.)

Yes, reflection in C# allows generic classes to be instantiated at runtime, but that's more complicated, more error-prone and slower, so it should only be done where the added flexibility is absolutely necessary.

Another difference between C# generics and C++ templates is much more significant. C# supports type parameter constraints and type-checks generic classes much like normal classes, whereas template classes are type-checked whenever they're instantiated.

C++'s concept is more flexible but has two significant drawbacks. First, type correctness of a template can not be proven by the compiler and has to be ensured through test instantiations, which of course can leave untested cases. Secondly, violations of the implicit constraints on template arguments lead to unhelpful error messages somewhere inside the template.

Recent C++ compilers can do some type-checking on templates, but that can only ever be partial because there are no explicit type constraints to check against.

The "Boost Concept Checking Library" for C++ uses some ingenious macro hackery to allow explicit template constraints and provide better error messages. But again that's only a partial solution because the template writer isn't required to provide these and the compiler cannot check that the template code actually adheres to the constraints.

Re: C# generics and C++ templates
by Scott S on Fri 6th Aug 2004 14:16 UTC

andy: Stroustrup wrote an interesting paper on the direction future C++ standards might go with concept checking. I read it a few months ago, so I can't recall the details, but I do remember being impressed with it, and thinking it was a more robust solution than what C# is doing.

Concept checking - A more abstract complement to type checking
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1510.pdf

RE: Credibility destroyed
by chris on Fri 6th Aug 2004 16:27 UTC

C++ templates are a compile-time feature much like a macro preprocessor
Andreas:
You're right; I should've been more detailed.

Comparing a macro preprocessor with a Turing-complete 'found' language like C++ templates, and says the one is 'much like' the other could be an indicator that one hasn't been looking at http://boost.org of late, nor read stuff like http://www.moderncppdesign.com/book/main.html or http://www.josuttis.com/tmplbook/

When you don't have time to delve into every technology (and who does) some (like me) key in on statements like the above as litmus tests for whether the author is worth reading.

RE: Credibility destroyed
by Andreas Huber on Fri 6th Aug 2004 20:17 UTC

Chris:

I agree with you comparison macros vs. templates.

I completely misinterpreted your very first post. I did not realize that you quoted the first sentence from the article and therefore took it as your own writing. Out of context, I thought that you think that generics are not a good solution for a highly dynamic language like C#.
You are right that this sentence in the article is easily misunderstood. However, I think the author wanted to say that he doesn't want generics to be a compile time only construct as they are in C++ and Java (templates do not exist in the compiled code, only instantiated templates do, as normal classes and normal functions).

Sorry,

Andreas

Generics and C#
by Eric Gunnerson on Tue 10th Aug 2004 16:06 UTC

It's certainly true that the current constraint system of generics in .NET isn't as rich as it could be. We are exploring where it makes sense to extend it in the future, but there will be no changes to the current scheme in C# V2.0. Note that any change to the generics constraint syntax impacts all .NET languages, so it's not just a C# thing.

There's one technique to make it a little nicer to write such things, though the perf isn't up to a hand-coded approach. See http://blogs.gotdotnet.com/EricGu/commentview.aspx/0efca2aa-0c7c-4a... for more information.

Re: Generics and C#
by Rüdiger Klaehn on Thu 12th Aug 2004 09:31 UTC

The IArithmetic<T> proposal would not require any changes to the constraint syntax. It would just require the base data types to implement another interface in addition to IComparable<T>.

I already came up with the IntCalculator approach, but since it involves a method call that is currently not inlined it is much too slow for my application (complex numbers and vectors).

But it is nice to know that you at microsoft are at least thinking about the problem.