(SOS) Strongly Request: Improve generic constraint in C#3.0 !!!

// Strongly Request: Improve generic constraint in C#3.0
/**********************************************************************************************************************************/
/* Now, in order to write a GenericType that support simple Arithmetics like "+ - * /" have to write like like the following
* You can see,The code is very ugly and troublesome, the performance is slow, and have to write Constraint for every class not under control
/**********************************************************************************************************************************/
public interface IArithmetics<T>
{
T Add(T a, T b);
T Subtract(T a, T b);
T Multiply(T a, T b);
T Divide(T a, T b);
}

public class GenericType<T, TConstraint>
where TConstraint : IArithmetics<T>, new()
{
private T _Value1;
private T _Value2;

private static readonly TConstraint _Constraint = new TConstraint();

#region Constructors
public GenericType(T value1, T value2)
{
this._Value1 = value1;
this._Value2 = value2;
}
#endregion

public static GenericType<T, TConstraint> operator +(GenericType<T, TConstraint> value1, GenericType<T, TConstraint> value2)
{
T valueSum1 = _Constraint.Add(value1._Value1, value2._Value1);
T valueSum2 = _Constraint.Add(value1._Value2, value2._Value2);

return new GenericType<T, TConstraint>(valueSum1, valueSum2);
}

// Other methods go here...
}

//In oder to use short,int and so on, have to write Int16Constraint,Int32Constraint and so on,endless and troublesome!
public struct Int32Constraint : IArithmetics<int>
{
#region IArithmetics<int> Members
public int Add(int a, int b) { return a + b; }
public int Subtract(int a, int b) { return a - b; }
public int Multiply(int a, int b) { return a * b; }
public int Divide(int a, int b) { return a / b; }
#endregion
}

//public struct Int16Constraint : IArithmetics<int> { /*....*/}
//public struct Int64Constraint : IArithmetics<long> { /*....*/}


/**********************************************************************************************************************************/
/* BUT if u can provide a new key 'constrant' like the following, the life will become good
/* constrant only used to provide compiler checking and intellisense.
/**********************************************************************************************************************************/

public constrant ArithmeticsConstraint<T>
{
public static T operator +(T value1, T value2);
public static T operator -(T value1, T value2);
public static T operator *(T value1, T value2);
public static T operator /(T value1, T value2);
}

public class GenericType<T>
where T : ArithmeticsConstraint<T>
{
private T _Value1;
private T _Value2;

#region Constructors
public GenericType(T value1, T value2)
{
this._Value1 = value1;
this._Value2 = value2;
}
#endregion

public static GenericType<T> operator +(GenericType<T> value1, GenericType<T> value2)
{
T valueSum1 = value1._Value1 + value2._Value1;
T valueSum2 = value1._Value2 + value2._Value2;

return new GenericType<T, TConstraint>(valueSum1, valueSum2);
}

// Other methods go here...
}

/**********************************************************************************************************************************/
/* The above is just simple case, the following are the more complex case.
/**********************************************************************************************************************************/
constrant TAllType : ISomeInterface,ISomeInterface2
{
//Constructors
public TAllType();
public TAllType(int i);

//Methods
public static bool operator ==(TClass t1, TClass t2);
public static bool operator +(TClass t1, TClass t2);
public void Method1();
public void Method2(TClass t, int i);

//Properties
public int Property1{get;set;}
public int this[int i]{get;}
}

//For class
class constrant TClass : ISomeInterface,ISomeInterface2,...
{
//Constructors
public TClass();
public TClass(int i);

//Methods
public static bool operator ==(TClass t1, TClass t2);
public static bool operator +(TClass t1, TClass t2);
public void Method1();
public void Method2(TClass t, int i);

//Properties
public int Property1{get;set;}
public int this[int i]{get;}
}

//For struct
struct constrant TStruct: ISomeInterface,ISomeInterface2,...
{
//Constructors
public TStruct();
public TStruct(int i);

//Static Methods
public static bool operator ==(TStruct t1, TStruct t2);
public static bool operator +(TStruct t1, TStruct t2);
public void Method1();
public void Method2(TStruct t, int i);

//Properties
public int Property1{get;set;}
public int this[int i]{get;}
}

//GenericClass use TClass,TStruct as normal class,compiler can give clear error message
public class GenericClass<TAll,TClass,TStruct>
//Note here use constrant class or struct directly
//"where" statement is not needed now
{
public void sample()
{
//here just treat TAll, TClass,TStruct as normal type, it's simple for compiler.
TAll all=new TAll(10);

TClass refObj = new TClass();
TClass refObj2 = new TClass(1);

TClass refObj3 = refObj + refObj2;

TStruct valueObj = new TStruct(100);
TStruct valueObj2 = new TStruct(10);

if (valueObj == valueObj2)
{
valueObj.Method1();
valueObj2.Method2();
}

int i=refObj3.Property1;
int j=valueObj2[0];

//if can support dynamic constrant,that's better, runtime can produce correct il for each type
#if(typeof(TAll)==typeof(int))
{
//do something for int ....
}
#else if(typeof(TAll)==typeof(decimal))
{
//do something for decimal ....
}
#else
{

}
}
}

public class UseGenericClass
{
public void Test()
{
//Compiler will check:
//RealType includes all signatures of TAll, but do not force RealType inherited from TAll;
//RealClass is class, includes all signatures of TClass, but do not force RealClass inherited from TClass;
//RealStruct is Struct, includes all signatures of TStruct
GenericClass<RealType, RealClass,RealStruct> obj=new GenericClass<RealClass,RealValue>();
}
}

[6972 byte] By [Jethro] at [2008-2-7]
# 1

Hi Jethro,

Thank you for your suggestion! Smile. This is not going to be in Orcas, but it is on our wishlist.

Other people suggested a somehow different solution, they suggest adding a keyword "has" and defining things like

T Square<T>(T a): where T has operator * (T, T)

{

return a * a;

}

So may be we will see some solution to this on some future version of C#

Regards,

Marcelo.

MarceloGuerra-MSFT at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...
# 2

I also think over the "has" suggestion, BUT i think it's not so good:

1. it can not be reuse. in my suggestion, constraint can be public and can be reused by every generic class if need.

2. it's not so intuitionistic and managable. in my suggestion, all related methods to achieve one purpose will be put in one Constrait, that's similar with Interface which has been acceptted by most programmer.

3. in my suggestion, Constrait can also has access modifier like interface and class.

4. if the IDE is so good, it's simple for ide to generate a Constrait from source code(do the work for programmers), and because it's centralized, then it's easy to be verified by programmer, especially for large class .

5. the "has" suggestion can be simple or speciall style of my suggestion.

6. How do they handle Properties and Public Fields and so on ? (Sorry, in my suggestion, Public Fields

has been omitted. )

7. the last, compiler checking maybe more fast(just think it should be Smile )

Jethro at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...
# 3

Hi,

Thanks for the follow up... I'll pass this to our design people...

MarceloGuerra-MSFT at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...
# 4
Hi!
I think it'll be enought to add some implemented interfaces to basic value types:
Code Snippet

public interface IAdding<T>

{

T Add(T value);

}

public interface ISubtraction<T>

{

T Sub(T value);

}

public interface IIncrement<T>

{

T Inc(T value);

}

and

public interface IAdding<TR, T0>

{

TR Add(T0 value);

}

then

public struct Int32: IAdding<Int32>, IAdding<Int32, Int32>, IIncrement<Int32>, ...

public class BigInteger: IAdding<BigInteger>, IAdding<BigInteger, uint>, ...

the use must be simple:

public struct Complex<T> where T: IAdding<T>, ISubtraction<T>, ...
{
}

Thanks.
Karioth at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...
# 5

my prefered syntax would be

where T + T : T

meaning there must exist a (static) T operator + (T,T)

It would allow using + in expressions

also:

where T - T : T

where - T : T (unary minus)

etc...

GillesMichard at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...
# 6

To Karioth

It's not enough, how do u to use all the classes that already been exists, not only that classes in .net framework! You can not let every classes to be changed, and let all new classes to implementation the interface just in order to use constraints

To GillesMichard

the constraints is bad in current version, the new constraints should resolve all the problem that was not resolved! not only "+" and so on. should let generic to be used freedomly.

Jethro at 2007-9-13 > top of Msdn Tech,Visual Studio Orcas,Visual C# Orcas...

Visual Studio Orcas

Site Classified