Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing arithmetic in generics?

Tags:

c#

.net

generics

Is it possible to implement basic arithmetic (at least addition) in C# generics, like you can with C++ templates? I've been trying for a while to get them up and working, but C# doesn't let you declare the same generic type multiple times, like you can with templates.

Extensive googling did not provide an answer.

EDIT: Thanks, but what I'm looking for is a way to do the arithmetic at compile time, embedding something like Church numerals in generics types. That's why I linked the article that I did. Arithmetic in generic types, not arithmetic on instances of generic types.

like image 477
Thom Smith Avatar asked Jun 08 '12 15:06

Thom Smith


People also ask

How are generics implemented in Java?

To implement generics, the Java compiler applies type erasure to: Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.

How do you add two generic values in Java?

You have to add the numbers as the same type, so you could do x. intValue() + y. intValue(); .

Do generics increase code performance?

Using this, the programmer will improve the performance of an application. In addition to performance, generics provide type-safety and higher quality code because you get to reuse data processing algorithms without duplicating type-specific code. Generics are also known as Parametric polymorphism.

Do generics use reflection?

Because the Common Language Runtime (CLR) has access to generic type information at run time, you can use reflection to obtain information about generic types in the same way as for non-generic types.


2 Answers

Unfortunately you cannot use arithmetic operations on generic types

T Add(T a, T b)
{
    return a + b; // compiler error here
}

will not work in c#!

But you can create your own numeric types and overload the operators (arithmetic, equality and implicit, explicit). This lets you work with them in a quite natural way. However you cannot create an inheritance hierarchy with generics. You will have to use a non generic base class or interface.

I just did it with a vector type. A shortened version here:

public class Vector
{
    private const double Eps = 1e-7;

    public Vector(double x, double y)
    {
        _x = x;
        _y = y;
    }

    private double _x;
    public double X
    {
        get { return _x; }
    }

    private double _y;
    public double Y
    {
        get { return _y; }
    }

    public static Vector operator +(Vector a, Vector b)
    {
        return new Vector(a._x + b._x, a._y + b._y);
    }

    public static Vector operator *(double d, Vector v)
    {
        return new Vector(d * v._x, d * v._y);
    }

    public static bool operator ==(Vector a, Vector b)
    {
        if (ReferenceEquals(a, null)) {
            return ReferenceEquals(b, null);
        }
        if (ReferenceEquals(b, null)) {
            return false;
        }
        return Math.Abs(a._x - b._x) < Eps && Math.Abs(a._y - b._y) < Eps;
    }

    public static bool operator !=(Vector a, Vector b)
    {
        return !(a == b);
    }

    public static implicit operator Vector(double[] point)
    {
        return new Vector(point[0], point[1]);
    }

    public static implicit operator Vector(PointF point)
    {
        return new Vector(point.X, point.Y);
    }

    public override int GetHashCode()
    {
        return _x.GetHashCode() ^ _y.GetHashCode();
    }

    public override bool Equals(object obj)
    {
        var other = obj as Vector;
        return other != null && Math.Abs(other._x - _x) < Eps && Math.Abs(other._y - _y) < Eps;
    }

    public override string ToString()
    {
        return String.Format("Vector({0:0.0000}, {1:0.0000})", _x, _y);
    }
}
like image 195
Olivier Jacot-Descombes Avatar answered Oct 11 '22 11:10

Olivier Jacot-Descombes


Please feel free to offer more clarification if my answer seems off-kilter.

There are no generic constraints on operators in the C# language, at least. As Jon Skeet has proven with Unconstrained Melody, the constraints might actually be perfectly valid in the CLR itself.

The best you can do with constraints is provide interfaces / custom classes that expose the actions you need. You wouldn't be able to provide the primitive (unless you also implement the implicit operator perhaps), but it would at least let you create generic code for the math part.

Generic constraints allow the compiler to infer the available members based on the lowest common denominator (as specified by the constraint or lack of). Most of the time, generics are unconstrained and thus give you only object semantics.


Alternatively, avoid using constraints and use dynamic to temporarily store the generic variable and then make the assumption (via duck typing) that it has the relevant operators:
class Program
{
    static void Main(string[] args)
    {
        var result = Add<int, long, float>(1, 2);
        Console.WriteLine(result); // 3
        Console.WriteLine(result.GetType().FullName); // System.Single
        Console.Read();
    }

    static T3 Add<T1, T2, T3>(T1 left, T2 right)
    {
        dynamic d1 = left;
        dynamic d2 = right;
        return (T3)(d1 + d2);
    }
}

This involves the DLR and will have some performance overhead (I don't have exact figures), especially if you intend the calculations to be performance-critical.


I'm not sure what you mean "declare the same generic type multiple times", this works:
class Tuple<T1, T2> // etc.

var myTuple = new Tuple<int, int>(1, 2);
like image 28
Adam Houldsworth Avatar answered Oct 11 '22 11:10

Adam Houldsworth