views:

617

answers:

6

Why cannot C# generics derive from one of the generic type parameters like they can in C++ templates? I mean I know it impossible because CLR does not support this, but why?

I am aware of the profound differences between C++ templates and C# generics - the former are compile time entities and must be resolved during the compilation, while the latter are first class run-time entities.

Still, I am failing to see the reason why CLR designers did not come up with a scheme which would ultimately enable a CLR generic type to derive from one of its generic type parameters. After all, this would be tremendously useful feature, I personally miss it greatly.

EDIT:

I would like to know of a hard-core issue, fixing which yields such a high price on implementing this feature that justifies it not being implemented yet. For instance, examine this fictional declaration:

class C<T> : T
{
}

As Eric Lippert has noticed what if "What if T is a struct? What if T is a sealed class type? What if T is an interface type? What if T is C?! What if T is a class dervied from C? What if T is an abstract type with an abstract method? What if T has less accessibility than C ? What if T is System.ValueType? (Can you have a non-struct which inherits from System.ValueType?) What about System.Delegate, System.Enum, and so on?"

As Eric continues, "Those are the easy, obvious ones". Indeed, he is right. I am interested in a concrete example of some neither easy nor obvious issue, which is hard to resolve.

A: 

C++ templates cannot be compared to C# generics. C++ templates are pre-processed like macros, while generics in .NET are handled by the runtime.

But there are other people who know a lot more about that than me...

Philippe Leybaert
+1  A: 

What would be so useful about this?

Remember that despite the name, generics were never intended to support generic programming.

To support a feature like this, they'd have to make some pretty dramatic changes to the CLR.

You'd need to define a class that derives from a type that doesn't even exist at compile-time.

Why should they jump through such hoops and pretty fundamentally compromise their type system just to add this feature? Is it worth it?

If you think so, tell them why. Write feedback on connect.microsoft.com telling them why this feature is so fundamental that it must be added.

jalf
+17  A: 

Well, start by asking yourself what could possibly go wrong with class C<T> : T { }. A huge number of things come immediately to mind:

What if T is a struct? What if T is a sealed class type? What if T is an interface type? What if T is C<T>?! What if T is a class dervied from C<T>? What if T is an abstract type with an abstract method? What if T has less accessibility than C ? What if T is System.ValueType? (Can you have a non-struct which inherits from System.ValueType?) What about System.Delegate, System.Enum, and so on?

Those are the easy, obvious ones. The proposed feature opens up literally hundreds, if not thousands of more subtle questions about the interaction between the type and its base type, all of which would have to be carefully specified, implemented and tested. We'd undoubtedly miss some, and thereby cause breaking changes in the future, or saddle the runtime with implementation-defined behaviour.

The costs would be enormous, so the benefit had better be enormous. I'm not seeing an enormous benefit here.

Eric Lippert
Do you find this feature less difficult to implement for C++ templates? Because it exists there and it is tremendously useful and exceptionally powerful. I can give one example when I would find this feature really useful, because that is related to my work at the moment. If you want to dynamically generate a type with Reflection.Emit, which base type is only known at run-time, then it would be hugely useful to have a statically compiled generic deriving from its type parameter, from which the dynamically emitted type could derive.
mark
The reasons you give are trivially verified and you have noticed rightfully so. I would like a concrete example of hard to solve issue.
mark
Updated my question.
mark
It is far less difficult to implement for C++ templates because C++ templates *recompile* the template on each construction of it. C# generics are compiled *once* and the same code is generated at runtime for ALL constructions if the type argument is a reference type. That's a fundamental difference; it means that C# generics must be correct for any *possible* construction, whereas C++ templates need only be correct for the finite number of *actual* constructions in the source code.
Eric Lippert
Good point. But generic types are open types. One cannot have any instances of an open generic type. Hence its actual memory layout may remain unresolved until a generic type is actually instantiated. In fact, this is the case even today. A generic type aggregating an instance of the generic parameter type has unclear memory layout until instantiation. At the moment I am not convinced that it is impossible to come up with a set of constraints (new types of constraints will be needed) to make the discussed inheritance work.
mark
+11  A: 

OK, if you didn't like my previous answer, then let's take a different tack.

Your question presupposes a falsehood: that we need a reason to not implement a feature. On the contrary, we need a very, very good reason to implement any feature. Features are enormously expensive in their up-front costs, in their maintenance costs, and in the opportunity costs. (That is, the time you spend on feature X is time you cannot spend on doing feature Y, and which might prevent you from ever doing feature Z.) In order to responsibly deliver value to our customers and stakeholders, we cannot implement every feature that someone happens to like.

It's not up to the runtime designers to justify why they did not implement a feature that you find particularly nice. Features are prioritized based on their costs vs the benefit to users, and users have not exactly been hammering down my door demanding this kind of inheritance. This particular feature would massively change how analysis of the type system works in the runtime, have far-reaching effects on every language that consumes generics, and seems to me to provide very little benefit.

We use this sort of inheritance in the compiler -- written in C++ -- and the resulting code is difficult to follow, hard to maintain, and confusing to debug. I've been doing my best to gradually eliminate code like this. I'm opposed to enabling the same sort of bad patterns in C# unless there is an enormously compelling benefit to doing so.

The task of describing that enormous benefit in a compelling way is laid upon the people who want the feature, not upon the people who would have to implement it. So what's the compelling benefit?

Eric Lippert
Granted, the way I have phrased my question may lead one to think so. The reason is that I, as a former C++ developer, think of the ability to inherit from the template parameter type as a very useful feature, used extensively in some important libraries - ATL and boost to name a few (I am not sure if STL uses it, probably). It was very natural for me to expect that .NET generics have it as well, despite the fundamental differences between C++ templates and .NET generics. I was greatly surprised to reveal they did not. That's why I presumed that MS wanted the feature, but chose not to do it.
mark
Anyway, I accept the challenge and try to collect compelling reasons why this feature would be great to have. For that I will start another community wiki question and let folks provide the reasons. I will add a comment with the link to the question as soon as I post it.
mark
http://stackoverflow.com/questions/1849107/what-are-the-good-reasons-to-wish-that-net-generics-could-inherit-one-of-the-gen
mark
A: 

Example of code, where this could help:

public class SpecialDataRow : T where T:DataRow { public int SpecialFactor {get; set;} }

This would enable making 'special' rows from DataRow and also from any derived DataRows (like typed dataset generated ones)

I do not see any other way how to code such a class

maliger
If you want to add methods to multiple descendants op DataRow, you could use extension methods.
oɔɯǝɹ
Good point. But you will add those methods to all instances, not only those 'special' ones (minor issue, imho)
maliger