A couple of weeks ago a friend was chatting to me in IM and asked me about a problem he was having with generics constraints. I told him he was trying to solve the lack of an INumeric interface issue. Then last week I watched Brian Beckman go through the same thing with generics, again unable to use a numeric constraint, instead having to create his own wrapper types. This issue is not new, it is well known. But what is still lacking is clear and open discussion from Microsoft on how to address this, Anyway, here's my point of view :
The numeric types can be grouped into two separate categories, Integer types, and Real types. The Integer group currently has 8 types in it, the signed types, SByte, Int16, Int32, Int64, and the unsigned types, Byte, UInt16, UInt32, UInt64. The Real group has 3 types, Decimal, Single and Double. Although all of these implement IConvertible, there is no other common base other than ValueType or Object. In particular, none of these types has defined operators or methods such as Add, instead the operators are provided by languages.
One option would be to include an INumeric interface. The problem with this is that it would need to have methods for all the standard operators, and overloads for combining with each of the other of the 11 numeric types. You couldn't have just one overload and cast to a wider type, as you would have no way to know if there was a wider type. It may also be advantageous to be able to work with Integer types as distinct from Reals for both performance reasons as well as allowing bitwise operators.
So, I believe the best solution is not an interface, but rather a language provided grouping, or set of groupings. I'm going to use 3 sets, Numeric:Integer, Numeric:Real, and Numeric:All. With these you would define a constraint such as
Function MoveRight(Of T As Numeric:Integer)(x As T) As T
return x >> 1
End Function
Or
Function AnnualIncrease(Of T As Numeric:Real)(salary As T) As T
return CType(salary * 1.1, T)
End Function
This still has difficulties in that constants are hard to express in the given type, although that could be handled with some compiler relaxation. For example in the above sample of AnnualIncrease, if you declared a variable of type T then assigned it the 1.1, the constant would be inferred based on T.
Function AnnualIncrease(Of T As Numeric:Real)(salary As T) As T
Dim increase As T = 1.1
return salary * increase
End Function
Because the Numerics are all value types, when using generics I believe they cause a new type to be laid out, one per value type, thus allowing the CLR to verify the type and the operations on those types. The operators for numeric types are in fact provided by the CLR at an intrinsic level. The problem being is they are often type specific for loading of constants, and some of the operators are different for signed versus unsigned operations. The basic operations such as add, divide, multiply, and, or, etc are the same for all the numeric types. So it seems that perhaps a little help form the CLR combined with a little flexibility from the languages, providing such a constraint wouldn't be that difficult at all.
It certainly would be nice to see it addressed.