explicit cast between generic types

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jon

    #1

    explicit cast between generic types

    Hi,

    When I try to compile the following generic class, the compiler gives
    me many errors "Cannot conver type '...' to '...'" on the lines
    indicated. Besides, the C# compiler gives me errors even if I don't
    declare and instantiate C_Filter_MA<Ti, Tsin my program.
    Ti and Ts should be one of {Byte, UInt16, UInt32, UInt64, SByte,
    Int16, Int32, Int64, double}.

    Any clue on how to be able to compile this class?
    Thank you very much.

    // =============== =============== =============== =============== ==
    public class C_Filter_MA<Ti, Ts>
    {
    // ............... ............... ............... ...............
    protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the
    items.
    protected Ts Ts_sum; // Sum of the values stored in the
    queue.
    ...
    // ............... ............... ............... ...............
    ...
    // ............... ............... ............... ...............
    public void Clear()
    {
    ...
    Ts_sum =(Ts)0; // <-- Compile error.
    ...
    } // Clear
    // ............... ............... ............... ...............
    public Ti InOutData(Ti Ti_in)
    {
    ...
    Ts_sum -=(Ts)Ti_queue.D equeue(); // <-- Compile error.
    ...
    Ts_sum +=(Ts)Ti_in; // <-- Compile error.
    ...
    } // InOutData
    // ............... ............... ............... ...............
    } // C_Filter_MA
    // =============== =============== =============== =============== ==

  • Nicholas Paldino [.NET/C# MVP]

    #2
    Re: explicit cast between generic types

    Jon,

    Why do you have two types to begin with? How is it that the sum of
    types Ti equals a ^NEW^ type Ts? Why wouldn't you just need one type, Ti?

    As for the Clear method, you can fix this by using default:

    public void Clear()
    {
    // This should probably be Ti, the same could be applied.
    Ts_sum = default(Ti);
    } // Clear

    If Ti is a blittable type, then an instance of that type will be created
    with the data set to 0 for all bits in the type. In the case of int,
    double, etc, etc, that means values of 0.

    Changing to Ti will fix the Dequeue issue as well.

    As for adding, you aren't going to be able to do much with that, since
    the constraint system doesn't tell the compiler anything about operations on
    a type. Because of this, you will need another class that handles this.
    First, you have to define an interface like this:

    interface ISimpleMath<T>
    {
    T Add(T value1, T value2);
    T Subtract(T value1, T value2);
    }

    Then, you implement it for each of the types you want to use, like so:

    class IntSimpleMath: ISimpleMath<int >
    {
    public int Add(int value1, int value2)
    {
    // Return the sum.
    return value1 + value2;
    }

    public int Subtract(int value1, int value2)
    {
    // Return the difference.
    return value1 - value2;
    }
    }

    Finally, you would add a second type to your generic type which would
    indicate the type used to perform the adding:

    public class C_Filter_MA<Ti, TSimpleMathwher e TSimpleMath:
    ISimpleMath<Ti> , new()
    {
    // Assuming that the operations on the implementation of ISimpleMath are
    thread-safe (and
    // they should be, since you are passing all operands into the method
    and not storing
    // shared state), you can store one instance and use that across all
    instances of the type.
    private static readonly SimpleMathImple mentation = new TSimpleMath();

    // ............... ............... ............... ...............
    protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the items.

    // Changed to be of type Ti.
    protected Ti Ts_sum; // Sum of the values stored in the queue.

    public void Clear()
    {
    Ts_sum = default(Ti)
    } // Clear

    public Ti InOutData(Ti Ti_in)
    {
    // Get the item.
    Ti item = Ti_queue.Dequeu e();

    // Subtract from the sum.
    Ts_sum = SimpleMathImple mentation.Subtr act(Ts_sum, item);

    // Add the item passed in.
    Ts_sum = SimpleMathImple mentation.Add(T s_sum, Ti_in);
    } // InOutData
    } // C_Filter_MA


    --
    - Nicholas Paldino [.NET/C# MVP]
    - mvp@spam.guard. caspershouse.co m

    "Jon" <jmp@hotmail.co mwrote in message
    news:mpsql3l6d6 5hsi36j968to1gd jrbl8urhr@4ax.c om...
    Hi,
    >
    When I try to compile the following generic class, the compiler gives
    me many errors "Cannot conver type '...' to '...'" on the lines
    indicated. Besides, the C# compiler gives me errors even if I don't
    declare and instantiate C_Filter_MA<Ti, Tsin my program.
    Ti and Ts should be one of {Byte, UInt16, UInt32, UInt64, SByte,
    Int16, Int32, Int64, double}.
    >
    Any clue on how to be able to compile this class?
    Thank you very much.
    >
    // =============== =============== =============== =============== ==
    public class C_Filter_MA<Ti, Ts>
    {
    // ............... ............... ............... ...............
    protected Queue<Ti Ti_queue; // Queue (FIFO) that stores the
    items.
    protected Ts Ts_sum; // Sum of the values stored in the
    queue.
    ...
    // ............... ............... ............... ...............
    ...
    // ............... ............... ............... ...............
    public void Clear()
    {
    ...
    Ts_sum =(Ts)0; // <-- Compile error.
    ...
    } // Clear
    // ............... ............... ............... ...............
    public Ti InOutData(Ti Ti_in)
    {
    ...
    Ts_sum -=(Ts)Ti_queue.D equeue(); // <-- Compile error.
    ...
    Ts_sum +=(Ts)Ti_in; // <-- Compile error.
    ...
    } // InOutData
    // ............... ............... ............... ...............
    } // C_Filter_MA
    // =============== =============== =============== =============== ==
    >

    Comment

    • Marc Gravell

      #3
      Re: explicit cast between generic types

      Ts_sum -=(Ts)Ti_queue.D equeue(); // <-- Compile error.
      Ts_sum +=(Ts)Ti_in; // <-- Compile error.

      For info, I have a working generic math implementation as an in-
      progress side project. It includes standard operators and conversion;
      it runtime (not compile-time) validated but is very fast.

      I posted some of it on this forum previously, but let me know if this
      is of interest.

      Marc

      Comment

      • Jon

        #4
        Re: explicit cast between generic types

        Hi Nicholas,

        I tried your custom interface solution. I end up with only 4 compile
        erros, in two lines. Search for token "errors" in the source code
        shown below. In line

        private static readonly Ts_SimpleMathIm plementation= new
        Ts_SimpleMath() ;

        it is like it doesn't know how to create a new instance of
        Ts_SimpleMath. The "new ()" in line

        where Ti_SimpleMath : I_SimpleMath<Ti >, new()

        presumably means that Ti_SimpleMath must have a public parameterless
        constructor. How can I specify the constructor of Ti_SimpleMath ? In
        I_SimpleMath<T> ? How?

        I know that I ended up not using "Ti_SimpleMathI mplementation", but I
        would keep it just in case. I do use "Ts_SimpleMathI mplementation".

        Sorry about the long post.

        If you know why I'm getting those errors, please let me know.
        Thank you.

        PS: I'm starting to think about not using generics for this purpose,
        and instead define two or three classes like "C_Filter_MA_u0 8_u32",
        "C_Filter_MA_u1 6_u32" and "C_Filter_MA_do uble_double", for instance,
        because I'll probably end up with fewer lines of code. All this has
        really surprised me.


        ---------------------------------------
        using System;
        using System.Collecti ons.Generic;

        // These "using" are the C# equivalent ones to "typedef" in C++.
        using u08 =System.Byte;
        using u16 =System.UInt16;
        using u32 =System.UInt32;
        using u64 =System.UInt64;

        using i08 =System.SByte;
        using i16 =System.Int16;
        using i32 =System.Int32;
        using i64 =System.Int64;

        namespace N_Filters
        {
        #region Interfaces and their implementations .
        // =============== =============== =============== =============== ===
        // Interfaces cannot contain operators.
        public interface I_SimpleMath<T>
        {
        T Add(T val1, T val2);
        T Subtract(T val1, T val2);
        T Multiply(T val1, T val2);
        T Divide(T val1, T val2);
        T ShiftLeft(T val1,u08 shift_amount);
        T ShiftRight(T val1,u08 shift_amount);
        } // I_SimpleMath
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_u0 8 : I_SimpleMath<u0 8>
        {
        public u08 Add(u08 val1, u08 val2)
        {
        return((u08)(va l1+val2));
        }
        public u08 Subtract(u08 val1, u08 val2)
        {
        return((u08)(va l1-val2));
        }
        public u08 Multiply(u08 val1, u08 val2)
        {
        return((u08)(va l1*val2));
        }
        public u08 Divide(u08 val1, u08 val2)
        {
        return((u08)(va l1/val2));
        }
        public u08 ShiftLeft(u08 val1,u08 shift_amount)
        {
        return((u08)(va l1<<shift_amoun t));
        }
        public u08 ShiftRight(u08 val1,u08 shift_amount)
        {
        return((u08)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_u0 8
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_u1 6 : I_SimpleMath<u1 6>
        {
        public u16 Add(u16 val1, u16 val2)
        {
        return((u16)(va l1+val2));
        }
        public u16 Subtract(u16 val1, u16 val2)
        {
        return((u16)(va l1-val2));
        }
        public u16 Multiply(u16 val1, u16 val2)
        {
        return((u16)(va l1*val2));
        }
        public u16 Divide(u16 val1, u16 val2)
        {
        return((u16)(va l1/val2));
        }
        public u16 ShiftLeft(u16 val1,u08 shift_amount)
        {
        return((u16)(va l1<<shift_amoun t));
        }
        public u16 ShiftRight(u16 val1,u08 shift_amount)
        {
        return((u16)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_u1 6
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_u3 2 : I_SimpleMath<u3 2>
        {
        public u32 Add(u32 val1, u32 val2)
        {
        return((u32)(va l1+val2));
        }
        public u32 Subtract(u32 val1, u32 val2)
        {
        return((u32)(va l1-val2));
        }
        public u32 Multiply(u32 val1, u32 val2)
        {
        return((u32)(va l1*val2));
        }
        public u32 Divide(u32 val1, u32 val2)
        {
        return((u32)(va l1/val2));
        }
        public u32 ShiftLeft(u32 val1,u08 shift_amount)
        {
        return((u32)(va l1<<shift_amoun t));
        }
        public u32 ShiftRight(u32 val1,u08 shift_amount)
        {
        return((u32)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_u3 2
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_u6 4 : I_SimpleMath<u6 4>
        {
        public u64 Add(u64 val1, u64 val2)
        {
        return((u64)(va l1+val2));
        }
        public u64 Subtract(u64 val1, u64 val2)
        {
        return((u64)(va l1-val2));
        }
        public u64 Multiply(u64 val1, u64 val2)
        {
        return((u64)(va l1*val2));
        }
        public u64 Divide(u64 val1, u64 val2)
        {
        return((u64)(va l1/val2));
        }
        public u64 ShiftLeft(u64 val1,u08 shift_amount)
        {
        return((u64)(va l1<<shift_amoun t));
        }
        public u64 ShiftRight(u64 val1,u08 shift_amount)
        {
        return((u64)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_u6 4
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_i0 8 : I_SimpleMath<i0 8>
        {
        public i08 Add(i08 val1, i08 val2)
        {
        return((i08)(va l1+val2));
        }
        public i08 Subtract(i08 val1, i08 val2)
        {
        return((i08)(va l1-val2));
        }
        public i08 Multiply(i08 val1, i08 val2)
        {
        return((i08)(va l1*val2));
        }
        public i08 Divide(i08 val1, i08 val2)
        {
        return((i08)(va l1/val2));
        }
        public i08 ShiftLeft(i08 val1,u08 shift_amount)
        {
        return((i08)(va l1<<shift_amoun t));
        }
        public i08 ShiftRight(i08 val1,u08 shift_amount)
        {
        return((i08)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_i0 8
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_i1 6 : I_SimpleMath<i1 6>
        {
        public i16 Add(i16 val1, i16 val2)
        {
        return((i16)(va l1+val2));
        }
        public i16 Subtract(i16 val1, i16 val2)
        {
        return((i16)(va l1-val2));
        }
        public i16 Multiply(i16 val1, i16 val2)
        {
        return((i16)(va l1*val2));
        }
        public i16 Divide(i16 val1, i16 val2)
        {
        return((i16)(va l1/val2));
        }
        public i16 ShiftLeft(i16 val1,u08 shift_amount)
        {
        return((i16)(va l1<<shift_amoun t));
        }
        public i16 ShiftRight(i16 val1,u08 shift_amount)
        {
        return((i16)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_i1 6
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_i3 2 : I_SimpleMath<i3 2>
        {
        public i32 Add(i32 val1, i32 val2)
        {
        return((i32)(va l1+val2));
        }
        public i32 Subtract(i32 val1, i32 val2)
        {
        return((i32)(va l1-val2));
        }
        public i32 Multiply(i32 val1, i32 val2)
        {
        return((i32)(va l1*val2));
        }
        public i32 Divide(i32 val1, i32 val2)
        {
        return((i32)(va l1/val2));
        }
        public i32 ShiftLeft(i32 val1,u08 shift_amount)
        {
        return((i32)(va l1<<shift_amoun t));
        }
        public i32 ShiftRight(i32 val1,u08 shift_amount)
        {
        return((i32)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_i3 2
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_i6 4 : I_SimpleMath<i6 4>
        {
        public i64 Add(i64 val1, i64 val2)
        {
        return((i64)(va l1+val2));
        }
        public i64 Subtract(i64 val1, i64 val2)
        {
        return((i64)(va l1-val2));
        }
        public i64 Multiply(i64 val1, i64 val2)
        {
        return((i64)(va l1*val2));
        }
        public i64 Divide(i64 val1, i64 val2)
        {
        return((i64)(va l1/val2));
        }
        public i64 ShiftLeft(i64 val1,u08 shift_amount)
        {
        return((i64)(va l1<<shift_amoun t));
        }
        public i64 ShiftRight(i64 val1,u08 shift_amount)
        {
        return((i64)(va l1>>shift_amoun t));
        }
        } // C_SimpleMath_i6 4
        // =============== =============== =============== =============== ===
        public class C_SimpleMath_do uble : I_SimpleMath<do uble>
        {
        public double Add(double val1, double val2)
        {
        return((double) (val1+val2));
        }
        public double Subtract(double val1, double val2)
        {
        return((double) (val1-val2));
        }
        public double Multiply(double val1, double val2)
        {
        return((double) (val1*val2));
        }
        public double Divide(double val1, double val2)
        {
        return((double) (val1/val2));
        }
        public double ShiftLeft(doubl e val1,u08 shift_amount)
        {
        return(val1*Mat h.Pow(2.0,(doub le)shift_amount ));
        }
        public double ShiftRight(doub le val1,u08 shift_amount)
        {
        return(val1*Mat h.Pow(2.0,(doub le)shift_amount *-1.0));
        }
        } // C_SimpleMath_do uble
        #endregion
        // =============== =============== =============== =============== ===
        // Moving average filter.
        // Ti = T_item {u08,u16,u32,u6 4,i08,i16,i32,i 64,double}.
        // Ts = T_sum {u08,u16,u32,u6 4,i08,i16,i32,i 64,double}.

        public class C_Filter_MA<Ti, Ti_SimpleMath,T s,Ts_SimpleMath >
        where Ti : IComparable, IFormattable, IConvertible,
        IComparable<Ti> , IEquatable<Ti>
        where Ti_SimpleMath : I_SimpleMath<Ti >, new()
        where Ts : IComparable, IFormattable, IConvertible,
        IComparable<Ts> , IEquatable<Ts>
        where Ts_SimpleMath : I_SimpleMath<Ts >, new()
        {
        // ............... ............... ............... ............... .
        private static readonly Ti_SimpleMathIm plementation= new
        Ti_SimpleMath() ; // <-- Compile errors "Invalid token '=' in class,
        struct, or interface member declaration" and "Class, struct, or
        interface method must have a return type".
        private static readonly Ts_SimpleMathIm plementation= new
        Ts_SimpleMath() ; // <-- Compile errors "Invalid token '=' in class,
        struct, or interface member declaration" and "Class, struct, or
        interface method must have a return type".
        // ............... ............... ............... ............... .
        protected Queue<Ti Ti_queue; // Queue (FIFO) that
        stores the items.
        public int Ti_queue_capaci ty; // Queue does not
        have any member field called Capacity.
        protected Ts Ts_sum; // Sum of the values
        stored in the queue.
        protected u08 u08_log2ofsize; // Log2(<size of
        fifo>). So, size of fifo will always be a power of 2.
        // ............... ............... ............... ............... .
        public C_Filter_MA(u08 u08_log2ofsize)
        {
        this.u08_log2of size=u08_log2of size;
        Ti_queue_capaci ty=1<<u08_log2o fsize;
        Ti_queue=new Queue<Ti>(Ti_qu eue_capacity);
        Clear();
        } // C_Filter_MA
        // ............... ............... ............... ............... .
        public void Clear()
        {
        Ti_queue.Clear( );
        Ts_sum=default( Ts);
        } // Clear
        // ............... ............... ............... ............... .
        public void Init(Ti Ti_initial)
        {
        Ti_queue.Clear( );

        Ts_sum=(Ts)Conv ert.ChangeType( Ti_initial.ToIn t32()*Ti_queue_ capacity,typeof (Ts));
        if (Ti_initial.Equ als(default(Ti) )) return;
        for (int i=0;i<Ti_queue_ capacity;i++)
        {
        Ti_queue.Enqueu e(Ti_initial);
        } // for
        } // Init
        // ............... ............... ............... ............... .
        public Ti InOutData(Ti Ti_in)
        {
        if (Ti_queue.Count >=Ti_queue_capa city)
        {

        Ts_sum=Ts_Simpl eMathImplementa tion.Subtract(T s_sum,(Ts)Conve rt.ChangeType(T i_queue.Dequeue (),typeof(Ts))) ;
        } // if
        Ti_queue.Enqueu e(Ti_in);

        Ts_sum=Ts_Simpl eMathImplementa tion.Add(Ts_sum ,(Ts)Convert.Ch angeType(Ti_in, typeof(Ts)));
        return(
        (Ti)Convert.Cha ngeType(Ts_Simp leMathImplement ation.ShiftRigh t(Ts_sum,u08_lo g2ofsize),typeo f(Ti))
        );
        } // InOutData
        // ............... ............... ............... ............... .
        } // C_Filter_MA
        // =============== =============== =============== =============== ===
        } // N_Filters

        Comment

        • Jon

          #5
          Re: explicit cast between generic types

          On Mon, 10 Dec 2007 14:27:33 -0800 (PST), Marc Gravell
          <marc.gravell@g mail.comwrote:
          Ts_sum -=(Ts)Ti_queue.D equeue(); // <-- Compile error.
          Ts_sum +=(Ts)Ti_in; // <-- Compile error.
          >
          >For info, I have a working generic math implementation as an in-
          >progress side project. It includes standard operators and conversion;
          >it runtime (not compile-time) validated but is very fast.
          >
          >I posted some of it on this forum previously, but let me know if this
          >is of interest.
          >
          >Marc
          Even though I prefer compile-time validation, I would be glad to take
          a look at your implementation. If you have a link, please let me know.
          Otherwise, please write me at "cucafera (at) telefonica (dot) com"

          Thank you.

          Comment

          • Marc Gravell

            #6
            Re: explicit cast between generic types

            I have e-mailed you a sample, but I've also just noticed that you
            mention CF. Unfortunately, the code doesn't compile in CF 3.5, as it
            uses some framework classes that aren't supported on that platform. It
            may be possible to re-work the concept using Delegate.Create Delegate
            and the various operators, but there are a lot of special cases where
            the operator is supplied by the compiler (not the Type) which would
            need surrogate methods (which is partly what I was hoping to avoid).

            Marc

            Comment

            • Ben Voigt [C++ MVP]

              #7
              Re: explicit cast between generic types

              but that didn't work either. It still doesn't know how to add or
              subtract. My quesion is: Isn't there any existing interface, which
              would be common to the integral and floating point types, which
              exposes methods so common as adding, subtracting, multiplying, etc?
              You've just nailed the biggest complaint about generics.


              Comment

              Working...