Rationale after the "literal" expression `where T : class` in C# - c#

In C#, one is allowed to write:
public class Foo<T> where T : class {
}
And according to the C# specifications, this means that:
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
Some are of the opinion that the literal statement T : class is confusing, one could see it as.
The type argument must be a class type. So interfaces and delegates are not allowed. (wrong)
Where for instances interfaces and delegates are not allowed. I'm wondering if the C# design team considered this and why they didn't introduce a constraint like:
where T : reference
(Or another keyword that is more precise). What was the rationale to use : class instead?

They wanted to stick to a keyword that was already present in the language. Surely reference or referencetype would be more precise.
Similarly, it is called where T : struct, not valuetype (or nonnullablevaluetype), even if both structs and enums are value types that can be used for T in that case. Also note that the special struct Nullable<> is not allowed if the constraint where T : struct was used.

where T: class
reads
where T: <reference type>
I'm not sure why it was called class, though. Someone who was sitting through the language team's meetings on that one might have to chime in.

Related

C# usage of where statement after function signature [duplicate]

I'm looking at the source code for the MvcContrib Grid and see the class declared as:
public class Grid<T> : IGrid<T> where T : class
What does the where T : class bit do?
It is a generic type constraint.
In this case it means that the generic type (T) must be a reference type, that is class, interface, delegate, or array type.
Other constraints are listed here.
You can also constrain the generic type to inherit from a specific type (base class or interface)
Another examples would be
public A<T> where T : AnInterface
where AnInterface is a interface class. It means then, that T must implement this interface.
These constraints are important, so that the compiler knows the operations which are valid for the type. For example you can not call functions of T without telling the compiler what functions the type provides.
From the Docs http://msdn.microsoft.com/en-us/library/d5x73970.aspx
where T : class
The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.
It is a constraint on the type argument which says that T can either be a class or an interface but not an enum or a struct. So T must be a reference type and not a value type.
Best Regards,
Oliver Hanappi
It restricts T to be a reference type, including any class, interface, delegate, or array type.
It's a generic type constraint. It specifies that the type T has to be a reference type, i.e. a class and not a structure.
you can apply restrictions to the kinds of types that client code can use for type arguments when it instantiates your class are called as Constraints on Type Parameters
E.g : where T : class
Here where T is the Type , The type argument must be a reference type; this applies also to any class, interface, delegate, or array type.

Class constraint must come before any other constraints

I am attempting to create the following class name signature:
public class MyClass<T> where T : struct, MyBase
(I am using struct to constrain to Enums)
I am getting error
The class type constraint 'MyBase' must come before any other constraints
I understand the message, however, rearranging the code I cannot get past that or some other syntax error. How can I fix that line if at all?
If I have to, I will remove struct.
Thank you
Constraints are "and-ed" together; all the constraints must be satisfied.
Under what circumstances can T be both a non-nullable value type and also be implicitly convertible to the class MyBase via identity, boxing or reference conversion?
There are no such circumstances, so there is no possible type argument that will satisfy T's constraints. Rather than letting you define a set of constraints that cannot be met, the compiler simply disallows it. You cannot state that you require both the struct constraint and a class type constraint.
I am using struct to constrain to Enums
That illustrates my point. Since there are no enums that inherit from MyBase, the constraint could not possibly be met.
Can you describe for me what you thought this meant? For example, did you think that it meant "any non-nullable value type or any type that is convertible to MyBase"? I am interested to learn why people believe false things about C# so that I can try to improve it.
UPDATE: Ah, I see -- MyBase is intended to be the base class of MyClass<T>, not the base class of T. In C#, it goes:
class [class name] < [generic type parameters] >
: [base classes and interfaces]
where [type parameter] : [constraints]
You have to put the base classes and interfaces before the constraints, otherwise the compiler thinks that they are the constraints.
Did you mean class MyClass<T> : MyBase where T : struct?
You're defining <T> as two different types.
struct is a value type where as MyBase is a class referring to a reference type.
It's not something that is interchangeable.
In this case it would be either:
public class MyClass<T> where T : struct
or
public class MyClass<T> where T : MyBase
Here is so more information regarding generics and how to use them.
If T must be a struct, it can't inherit from any other type... Value types don't support inheritance.
Not 100% sure on this, but a quick check of MSDN comes up with this where (generic type constraint) (C# Reference):
public class MyClass<T, U> where T : MyBase where U : struct
Not sure that's what you're looking for though.

Combining struct and new() generic type constraints

Having recently had reason to peruse the Nullable documentation, I noticed that the definition of Nullable looks like:
public struct Nullable<T> where T : struct, new()
I was of the (mis?)understanding that structs always have a public parameterless constructor, if this is correct, what does the new() type constraint add here?
For struct new doesn't make sense. For classes it does.
In your case it is a redundant.
public T FactoryCreateInstance<T>() where T : new()
{
return new T();
}
It make sense to specify new constraint in a case like above but not when it is already constrained to be struct.
Parameter less constructor for value types is a C# restriction and not a CLI restriction. Maybe this is why is it specified redundantly to leave some wiggle room for future.
It doesn't have to have a parameterless constructor, and even if it does have one it doesn't have to be a public one. I believe that "new()" requires it to have both these things.
Edit: Yup, as per the MSDN documentation: "The new constraint specifies that any type argument in a generic class declaration must have a public parameterless constructor."
Just noting this is valid, verifiable IL (i.e.
.class public sequential ansi sealed StructNewStruct`1<valuetype .ctor ([mscorlib]System.ValueType) T>
extends [mscorlib]System.ValueType
compiles, as does the simpler
.class public sequential ansi sealed StructNewStruct`1<valuetype .ctor T>
extends [mscorlib]System.ValueType
) but I don't yet have code that does anything different for these that a simple where T:struct (or (Of T As Structure) in VB.NET and <valuetype T> in IL) provides.
Specifically, Nullable structs are already not allowed for any generic argument with a simple struct constraint. (It does seem Nullable objects are classes for almost all purposes except storage.)
So, in summary, Nullable<T>'s current (equivalent of) where T:ValueType, struct, new() seems to currently be identical to where T:struct.
For your information I used my updated DotLisp that allows the creation of generic types (just using MakeGenericType) to attempt to create a type of StructNewStruct<t> and StructStruct<t>(*) for all types in all assemblies of the 4.0 Framework that load without me trying to load "unusual" assemblies (e.g. System.Web may not have been loaded). (If there are any "special" types in "obscure" framework assemblies let me know and I'll ensure they're loaded and tried.) All types succeeded or failed the same with both structures.
(*) StructStruct<T> where T:struct

Why Do I need to redeclare type constraint in generic subclass

Recently I tried to create a generic subclass by implementing a generic interface.
public interface IModule<T> where T : DataBean { ..... }
public class Module<T> : IModule<T> where T : DataBean { .... }
It seems I can't rely on any of T's restrictions as were defined in the base interface,
and I need to re-declare them myself.
MSDN just provided:
When using the subclass generic type
parameters, you must repeat any
constraints stipulated at the base
class level at the subclass level. For
example, derivation constraint
Why isn't it possible to infer the constraints from the base class/interface ?
I can't come up with any reason that the c# couldn't theoretically copy over constraints. But the documented behavior of making us copy (or augment) them explicitly seems to be the simplest way for usability.
public class A{}
public class B : A {}
public class X<T> where T: A {}
public class Y<T> : X<T> where T: B { }
In the above, note that I did not have to explicty copy over the constraint on Y<T>, because a B is always an A.
Now lets look at what happens if the "compiler automatically copies over constraints". Let's say I define Y<T> without constraints and the compiler places them automatically. I use Y<T> in lots of code. Then I change the constraints on the declaration of X<T> to include some new interface.
The compiler errors for changing the declaration of X<T> are at the sites where I use Y<T> !
With the way the c# compiler currently works, the compiler errors are at the usages of X<T>, as I would expect if I change it in a breaking way.
So while it would be convenient in some scenarios, it would also be somewhat confusing in others. While both are valid approaches, I would assume (note that I'm not able to read the minds of the c# design team) that it was a judgement call and not a purely technical one.
I say "not purely technical", but I can certainly imagine some interface scenarios where it would be somewhat simpler to verify that all constraints are met, rather than produce the simplest constraint that meets all required inherited constraints.
Standard C# team wisdom. Declarations should be self-documenting. And most of all, a change in one type declaration should not alter the behavior of an unrelated other type without generating a diagnostic. The -100 points principle put into design is another take on that.
The constranints on the interface are too vauge to tell the compiler what constraints the Module class should have. For example, the Module class could have a constraint on a super-class (inherited class) of DataBean.
I don't know the wisdom of the C# designers. Because the constraints can be different, I think a decision was made to have the developer explicitly declare the constraint rather than having the compiler make assumptions.

Generic class with restricted Type parameter

I want to create a generic class that takes a type parameter and restrict that parameter to numeric types or more generally to any type upon which the increment operator ++ can be applied.
I know I can do the following to restrict to structs but obviously there are structs that aren't numeric types and for which the ++ operator is not supported. Can I do this in C#
class Example<T> where T : struct
{
//Implementation detail
}
Unfortunately this is not possible (see here.) You can only constrain the type to:
Implement a specific interface or derive from a specific class
Be a class or struct
Have a parameterless constructor
Constraining types to have specific operators is a much-requested feature but I believe it will not be in C# 4 either.

Categories