Why don’t number types share a common interface?

Update

Generic math is coming as a preview feature to .NET 6. Read the announcement in the .NET dev blog:

Preview Features in .NET 6 – Generic Math


If you want to do such kind of “generic” arithmetics your option in a strongly-typed language such as C# are quite limited. Marc Gravell described the problem as follows:

.NET 2.0 introduced generics into the .NET world, which opened the door for many elegant solutions to existing problems. Generic constraints can be used to restrict the type-arguments to known interfaces etc, to ensure access to functionality – or for simple equality/inequality tests the Comparer<T>.Default and EqualityComparer<T>.Default singletons implement IComparer<T> and IEqualityComparer<T> respectively (allowing us to sort elements for instance, without having to know anything about the “T” in question).

With all this, though, there is still a big gap when it comes to operators. Because operators are declared as static methods, there is no IMath<T> or similar equivalent interface that all the numeric types implement; and indeed, the flexibility of operators would make this very hard to do in a meaningful way. Worse: many of the operators on primitive types don’t even exist as operators; instead there are direct IL methods. To make the situation even more complex, Nullable<> demands the concept of “lifted operators”, where the inner “T” describes the operators applicable to the nullable type – but this is implemented as a language feature, and is not provided by the runtime (making reflection even more fun).

However, C# 4.0 introduced the dynamic keyword which you can use to choose the correct overload at runtime:

using System;

public class Program
{
    static dynamic Min(dynamic a, dynamic b)
    {
        return Math.Min(a, b);        
    }

    static void Main(string[] args)
    {
        int i = Min(3, 4);
        double d = Min(3.0, 4.0);
    }
}

You should be aware that this removes type-safety and you might get exceptions at runtime if the dynamic runtime cannot find a suitable overload to call, e.g. because you mixed types.

If you want to get type-safety you might want to have a look at the classes available in the MiscUtil library providing generic operators for basic operations.

Please note that if you are only after specific operations you actually might use the interfaces that the built-in types already implement. For example, a type-safe generic Min function could look like this:

public static T Min<T>(params T[] values) where T : IComparable<T>
{
    T min = values[0];
    foreach (var item in values.Skip(1))
    {
        if (item.CompareTo(min) < 0)
            min = item;
    }
    return min;
}

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)