none
Templating any number RRS feed

  • Question

  • I'm trying to make a class that can hold a set of any one type of number, and then would allow me to perform standard numeric operations on it's elements (at least addition, subtraction, multiplication, division, comparison). I can't seem to find a method with generics to limit it to numeric types. All of the numeric structs seem to implement interfaces that (a) don't provide these operations, and (b) none seem to be limited to just numbers. I need at least int, long, float and double. Having byte, short and decimal wouldn't hurt, but aren't needed.

    Is there a way to do this? I can't be the first person who has wanted to do this.

    * Two thoughts I've had for this - an INumeric template - which covers the basic shared math operators.

    * I can see how this would potentially be hard to implement, but an 'adopt' mechanism for interfaces. It would be used in the form of: adopt(template parameters if applicable) : class...

    i.e.

    interface IMyNumeric<T>
      adopt(int) : int
      adopt(long) : long
      adopt(float) : float
      adopt(double) : double
    {
      static IMyNumeric<T> operator +(IMyNumeric<T> l, IMyNumeric<T> r);
      /*...*/
    }
    Of course, the problem with this, is you cant have interfaces define static stuff.


    Imagine a great looking signature here.

    Thursday, September 20, 2012 1:09 PM

Answers

  • This (Adding IArithmetic<T>) has been a very highly, long term requested feature on Connect.  However, after VS 2012 released, they pulled it from teh site.

    That being said, there are some workarounds.  The easiest is to use C# 4's dynamic, as that lets you handle this at runtime.  People have come up with other various workarounds, which work with some level of success.  For example, see: http://stackoverflow.com/a/147656/65358


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by Jim Stapleton Friday, September 21, 2012 9:42 AM
    Thursday, September 20, 2012 4:00 PM
    Moderator
  • The main advantage of returning dynamic would be that the caller would also get dynamic binding, which would allow them to use it as other types without casts.  If you return object, you'll force the caller/user of your class to cast as they pull out values, ie:

    // With dynamic, this will be allowed, since dynamic binding will do the conversion:
    double value2 = someVector.X;
    
    // With object, a cast is required:
    double value3 = (double)someVector.X;
    
    

    That being said, you ~could~ work around this by returning a "T" directly, and performing the cast internally.  Just realize that your'e going to be boxing/unboxing, so the performance using object/dynamic as above will not be as good as using generics directly would be, theoretically.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by Jim Stapleton Sunday, September 23, 2012 1:58 AM
    Friday, September 21, 2012 3:46 PM
    Moderator

All replies

  • This (Adding IArithmetic<T>) has been a very highly, long term requested feature on Connect.  However, after VS 2012 released, they pulled it from teh site.

    That being said, there are some workarounds.  The easiest is to use C# 4's dynamic, as that lets you handle this at runtime.  People have come up with other various workarounds, which work with some level of success.  For example, see: http://stackoverflow.com/a/147656/65358


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by Jim Stapleton Friday, September 21, 2012 9:42 AM
    Thursday, September 20, 2012 4:00 PM
    Moderator
  • Thanks. Yes, as I showed with the 'adopt' example, it would require an implementation of statics inheritance to keep the operators, for which there seems to be a major aversion in the .NET creators design ideas (this is the second time I've found it would have been nice).

    On a side note, I wonder if anyone sees the 'adopt' idea as being useful/interesting?


    Imagine a great looking signature here.

    Friday, September 21, 2012 9:47 AM
  • Also, what are the advantages over having the value stored in an object variable?

    i.e.

    public class Vector3D<T>
    {
      private dynamic _x,_y,_z;
      public dynamic x
      {
        get { return x; }
        set
        {
          if(value.GetType() != typeof(T))
            throw new ArgumentException(this.GetType().FullName + "Cannot accept axis values of type " + value.GetType().FullName);
          _x = value;
        }
      }
    }

    vs...

    public class Vector3D<T>
    {
      private dynamic _x,_y,_z;
      public dynamic x
      {
        get { return x; }
        set
        {
          if(value.GetType() != typeof(T))
            throw new ArgumentException(this.GetType().FullName + "Cannot accept axis values of type " + value.GetType().FullName);
          _x = value;
        }
      }
    }

    public class Vector3D<T>
    {
      private object _x,_y,_z;
      public object x
      {
        get { return x; }
        set
        {
          if(value.GetType() != typeof(T))
            throw new ArgumentException(this.GetType().FullName + "Cannot accept axis values of type " + value.GetType().FullName);
          _x = value;
        }
      }
    }


    Imagine a great looking signature here.

    Friday, September 21, 2012 10:02 AM
  • The main advantage of returning dynamic would be that the caller would also get dynamic binding, which would allow them to use it as other types without casts.  If you return object, you'll force the caller/user of your class to cast as they pull out values, ie:

    // With dynamic, this will be allowed, since dynamic binding will do the conversion:
    double value2 = someVector.X;
    
    // With object, a cast is required:
    double value3 = (double)someVector.X;
    
    

    That being said, you ~could~ work around this by returning a "T" directly, and performing the cast internally.  Just realize that your'e going to be boxing/unboxing, so the performance using object/dynamic as above will not be as good as using generics directly would be, theoretically.


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".

    • Marked as answer by Jim Stapleton Sunday, September 23, 2012 1:58 AM
    Friday, September 21, 2012 3:46 PM
    Moderator