Why Cannot C# Generics Derive from One of the Generic Type Parameters Like They Can in C++ Templates

In C# 4.0, is it possible to derive a class from a generic type parameter?

No, this is not possible. For example, take a type that is declared sealed. You can't inherit from that class, and there is no constraint to limit to non sealed types, ergo trying to inherit from it via a generic parameter is impossible.

Why can't the C# compiler deduce type parameters for return values?

I would recommend you to have a look at section 7.5.2 in the C# specification.

7.5.2 Type inference

When a generic method is called without specifying type arguments, a
type inference process attempts to infer type arguments for the call.
The presence of type inference allows a more convenient syntax to be
used for calling a generic method, and allows the programmer to avoid
specifying redundant type information.

[...]

Type inference occurs as part of the binding-time processing of a method invocation (§7.6.5.1) and takes place before the overload resolution step of the invocation [...]

Ie the resolution takes place before any kind of overload resolution is done, the problem is that inferring the types the way you said is not even tried, and is frankly not always possible either.

Type resolution for the arguments for generic types is only done with the arguments in the invocation! In you example only a string! It cannot infer int from the arguments, only the invocation context which isn't resolved at the time of the generic type-resolution.

Work around for deriving from a generic type parameter

A solution would be to not use generics at all and to use a factory pattern. Instead of having a generic parameter with the BaseClass and the new() constraint. Type everything BaseClass and provide a factory for new(). This can be either a full-fleged factory class or a lightweight factory delegate.

public interface IProtocolFactory
{
ProtocolBaseClass Create();
}

public class SomeDerivedProtocolFactory : IProtocolFactory
{
public ProtocolBaseClass Create()
{
return new SomeDerivedProtocol();
}
}

You might even add additional initialization code in the factory.

public class ReportProxy
{
private IProtocolFactory _factory;

public ReportProxy(IProtocolFactory factory)
{
_factory = factory;
}

public void DoSomething()
{
ProtocolBaseClass protocol = _factory.Create();
...
}
}

Using a delegate

    private Func<ProtocolBaseClass> _createProtocol;

public ReportProxy(Func<ProtocolBaseClass> createProtocol)
{
_createProtocol= createProtocol;
}

public void DoSomething()
{
ProtocolBaseClass protocol = _createProtocol();
...
}

What makes a template different from a generic?

Hm.. if you say you understand C++ templates in depth and say that you don't see/feel the difference between generics and them, well, that most probably you are right :)

There are many differences that will describe how/why generics are better than templates, list tons of differences, etc, but that's mostly irrelevant to the core of the idea.

The idea is to allow better code reuse. Templates/generics provide you a way to build a some kind of higher-order class definitions that abstract over some of the actual types.

In this terms, there is no difference between them, and the only differences are those enforced by specific features and constraints of the underlying language and runtime.

One may argue that generics provide some extra features (usually when talking about dynamic introspection of object's class tree), but very few of them (if any at all) cannot be implemented manually in C++'s templates. With some effort, most of them can be implemented, or emulated, hence they are not good as a distinction between 'proper generics' and 'real templates'.

Others will argue that the sheer potential power of optimization that is available thanks to the C++'s copy-paste behavior is the difference. Sorry, not true. JITs in Java and C# can do it too, well, almost, but do it very well.

There is however one thing that really could make the Java/C#'s generics a true subset of C++'s templates features. And you even have mentioned it!

It is template specialization.

In C++, each specialization behaves as a completely different definition.

In C++, template<typename T> Foo specialized to T==int may look like:

class Foo<int> 
{
void hug_me();

int hugs_count() const;
}

while "the same" template specialized to T==MyNumericType may look like

class Foo<MyNumericType> 
{
void hug_me();

MyNumericType get_value() const;
void reset_value() const;
}

FYI: that's just pseudocode, won't compile:)

Neither Java's nor C#'s generics can do that, because their definition states that all generic-type-materializations will have the same "user interface".

More to it, C++ uses a SFINAE rule. Many "theoretically colliding" specializations' definitions may exist for a template. However, when the template is being used, only those "actually good" are used.

With classes similar to the example above, if you use:

 Foo<double> foood;
foood.reset_value();

only the second specialization would be used, as the first one would not compile because of ... "reset_value" missing.

With generics, you cannot do that. You'd need to create a generic class that has all possible methods, and then that would at runtime dynamically inspect the inner objects and throw some 'not implemented' or 'not supported' exceptions for unavailable methods. That's... just awful. Such things should be possible at compile-time.

The actual power, implications, problems and overall complexity of template specialization and SFINAE is what truly differentiates the generics and templates. Simply, generics are defined in a such way, that specialization is not possible, hence SFINAE is not possible, hence, the whole mechanism is paradoxically much easier/simplier.

Both easier/simplier to implement in the compiler's internals, and to be understood by non-savant brains.

Although I agree with the overall benefits of generics in Java/C#, I really miss the specializations, interface flexibility, and SFINAE rule. However, I would not be fair if I'd not mention one important thing related to sane OO design: if you template-specialization for type xxx actually changes it's client API, then most probably it should be named differently and should form a different template. All the extra goodies that templates can do were mostly added to the tools set because ... in C++ there was no reflection and it had to be emulated somehow. SFINAE is a form of compile-time reflection.

Hence, the biggest player in the world of differences gets reduced to a curious (beneficial) sideeffect of a hotfix applied to mask the runtime's deficiency, which is the almost complete lack of runtime introspection :))

Therefore, I say that there are no difference other than some arbitrary ones enforced by laguage, or some arbitrary ones enforced by the runtime platform.

All of them are just a form of higher-order classes or functions/methods, and I think that this is the most important thing and feature.

Can't operator == be applied to generic types in C#?

"...by default == behaves as described above for both predefined and user-defined reference types."

Type T is not necessarily a reference type, so the compiler can't make that assumption.

However, this will compile because it is more explicit:

    bool Compare<T>(T x, T y) where T : class
{
return x == y;
}

Follow up to additional question, "But, in case I'm using a reference type, would the the == operator use the predefined reference comparison, or would it use the overloaded version of the operator if a type defined one?"

I would have thought that == on the Generics would use the overloaded version, but the following test demonstrates otherwise. Interesting... I'd love to know why! If someone knows please share.

namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();

Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);

}

static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}

class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}

public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}

Output

Inline:
Overloaded == called

Generic:

Press any key to continue . . .

Follow Up 2

I do want to point out that changing my compare method to

    static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}

causes the overloaded == operator to be called. I guess without specifying the type (as a where), the compiler can't infer that it should use the overloaded operator... though I'd think that it would have enough information to make that decision even without specifying the type.

C# generics vs C++ templates - need a clarification about constraints

Well, in general, C++ templates and C# generics are similar - compared to Java generics which are completely different, but they have also large differences. Like in C#, there is runtime support by using reflection, getting an object describing the types used to instantiate a generics. C++ doesn't have reflection, and all it does with types is done at compile time.

The biggest difference between C# generics and C++ templates indeed are that C# generics are better type checked. They are always constrained, in the sense that they don't allow operations that are not stated valid at the time of defining the generics. C#'s chief designer raised as a reason of that the added complexity it would have taken to have implied constraints. I'm not well versed with C#, so i can't talk further here. I'll talk about about how matters are in C++ and how they are going to be improved, so that people don't think C++'s stuff is all wrong.

In C++, templates are not constrained. If you do an operation, at template definition time it is implied that the operation will succeed at instantiation time. It's not even required to a C++ compiler that the template is syntactically checked for validity. If it contains a syntax error, then that error has to be diagnosed at instantiation. Any diagnose before that is a pure goody of the implementation.

Those implied constraint have shown to be easy for the template designer in the short term, because they don't have to care about stating the valid operations in their template interface. They put the burden on the user of their template - so the user has to make sure he fulfills all those requirements. Often it happens that the user tries seemingly valid operations but fails, with the compiler giving the user hundreds of lines of error messages about some invalid syntax or not found names. Because the compiler can't know what constraint in particular was violated in the first place, it lists all parts of code paths ever involved around the faulty place and all not even important details, and the user will have to crawl through the horrible error message text.

That is a fundamental problem, which can be solved by just stating at the interface for a template or generics what properties a type parameter has to have. C#, as far as i know it, can constraint the parameter to implement an interface or inherit a base-class. It solves that on a type-level.

The C++ committee has long seen there is need to fix these problems, and soon (next year, probably), C++ will have a way to state such explicit constraints too (see time-machine note below), as in the following case.

template<typename T> requires VariableType<T>
T f(T a, T b) {
return a + b;
}

The compiler signals an error at that point, because the expression as written is not marked valid by the requirements. This first helps the designer of the template to write more correct code, because the code is type-checked already to some degree (well to what is possible there). The programmer can now state that requirement:

template<typename T> requires VariableType<T> && HasPlus<T, T>
T f(T a, T b) {
return a + b;
}

Now, it will compiler. The compiler, by seeing T appearing as the return type, automatically implied that T is copyable, because that use of T appears in the interface, rather than in the templates body. The other requirements were stated using requirement clauses. Now, the user will get a appropriate error message if he uses a type that doesn't have an op+ defined.

C++1x decouples the requirements from the type. The above works for primitive types aswell as for classes. In this sense, they are more flexible, but quite a bit complex. The rules that state when and when requirements are satisfied are long... You can with the new rules say the following:

template<typename T> requires MyCuteType<T>
void f(T t) { *t = 10; }

And then, call f with an int! That would work by just writing a concept map for MyCuteType<int> that teaches the compiler how an int can be dereferenced. It will get quite handy in loops like this:

for_each(0, 100, doSomething());

Since the programmer can tell the compiler how an int can satisfy the concept of an input iterator, you could actually write such code in C++1x, if you only write the appropriate concept map, which really isn't all that difficult.

Ok, enough with this. I hope i could show you that having templates constrained is not all that bad, but in fact better, because the relationship betweens types and the operations on them within the templates are now known by the compiler. And i haven't even written about axioms, which are another nice thing in C++1x' concepts. Remember that this is future stuff, it's not yet out, but it will approximately at 2010. Then we will have to wait for some compiler to implement that all :)


UPDATE FROM "FUTURE"

C++0x concepts were not accepted into the draft but have been voted out at late of 2009. Too bad! But perhaps we will see it again in the next C++ version? Let's all hope!

Why does C# forbid generic attribute types?

Well, I can't answer why it's not available, but I can confirm that it's not a CLI issue. The CLI spec doesn't mention it (as far as I can see) and if you use IL directly you can create a generic attribute. The part of the C# 3 spec that bans it - section 10.1.4 "Class base specification" doesn't give any justification.

The annotated ECMA C# 2 spec doesn't give any helpful information either, although it does provide an example of what's not allowed.

My copy of the annotated C# 3 spec should arrive tomorrow... I'll see if that gives any more information. Anyway, it's definitely a language decision rather than a runtime one.

EDIT: Answer from Eric Lippert (paraphrased): no particular reason, except to avoid complexity in both the language and compiler for a use case which doesn't add much value.



Related Topics



Leave a reply



Submit