1

I'm currently implementing a simple version of algorithmic differentiation with operator overloading in C#. I'm trying to figure out how to design generic math functions that works for with ordinary doubles and my own class "ADouble" that works like a double, but overloads arithmetic operators like +,*,- and so forth.

For instance, i would like to create a function like

Public T MathFunction<T>(T x) where T : "is either double or Adouble"
{
    if (x > 0)
         return new T(1.0)
    else
        // something
}

that works for both doubles and ADoubles. In this case it's necessary for me to "new up" a specific value (here 1.0). In other cases i might have to do something like

Public T MathFunction<T>(T x) where T : "is either double or Adouble"
{
     T temporaryVar = 2*x;
     // .. More calculations
     return "some T";
}

I have implemented the necessary interfaces to do a comparison like the above, but i cannot get the rest to work.

I can instantiate my ADouble class with a double by, say

Adouble myADouble = new ADouble(12.3);

but doubles does not have a constructor that works that way, obviously. I've tried different things. First of all i thought of something like

if (typeof(T) == typeof(ADouble)
    return new ADouble(1.0)

but this does not work, since the function cannot cast ADouble to a T explicitly (which i understand).

Does anyone have a suggestion on how i could go about implementing generic calculation functions that works with my ADouble class and doubles? Or is the only option to make multiple methods with different signatures? Different suggestions for designs is also greatly appreciated.

amri
  • 77
  • 8
  • AFAIK you can't use `x or y` in generic constraints. You could create one method with a `dynamic` parameter and test inside if it's `double` or `ADouble` and if not throw an invalid argument exception. – Zohar Peled Apr 06 '17 at 19:17
  • You can take advantage of interfaces that the `Double` type implements such as `IConvertible`, `IComparable`, or `IEquatable`. – Dustin Kingen Apr 06 '17 at 19:19
  • Another alternative is to build [Expressions](https://msdn.microsoft.com/en-us/library/system.linq.expressions.expression.aspx). – Dustin Kingen Apr 06 '17 at 19:24

1 Answers1

1

Or is the only option to make multiple methods with different signatures?

Called "method overloading".

Yes. This is the correct way to express your "type A or type B" constraint, especially since even if you could successfully express that as a generic constraint, you are still left with the challenge of calling the appropriate constructor.

There is no mechanism in C# generics by which the statement return new T(1.0); could be made to compile successfully. Doing so would require some syntax that additionally constrains the types to those with a constructor that has a single parameter of type double, and there is no such feature in C#.

this does not work, since the function cannot cast ADouble to a T explicitly

Actually, it's that it can't cast implicitly. But, close enough. :)

That would be the next hurdle you'd have to clear. Ironically, this is the simplest. The issue there is that, as you wrote the expression, the compiler knows enough about what's going on to know it can't guarantee the cast will succeed. But if you cast the value to object first, you can then cast it to T without the compiler complaining.

Not that I'm suggesting doing that, mind you. The real issue here is that you are trying to use generic syntax for something that really isn't generic. Generic code is for where you can use any type, or at least a broadly constrained type. If you have specific types in mind, and especially if the implementation is different for each specific type, then you should not be using generics.

In that situation, method overloading is much more appropriate.


Aside: assuming your ADouble type is literally equivalent to double, and you can implement a conversion without any loss of data, you should consider writing an implicit conversion, to help make the types interchangeable. That would look something like this:

public static implicit operator ADouble(double value)
{
    return new ADouble(value);
}

Then you can initialize ADouble values with simple assignments, like:

ADouble adouble = 1.0;
Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
  • Thanks for the detailed explanation. Especially the last part. That is very helpful. What i ended up doing was to implement all my math methods for ADouble and then make an overloaded version that returns a double and takes as input doubles, and then using your implicit conversion method call the ADouble version of the method. This works fine for now. – amri Apr 07 '17 at 06:46