none
Deriving from Generic Base Classes RRS feed

  • Question

  • I'm currently working on a Linear Algebra library for .NET, and I wanted to make it as generic as possible so that I could implement "reference" classes, and other developers could later derive from these classes to include their own optimized algorithms (e.g. P/Invoking a DLL for calls to BLAS/ATLAS).

    For the absolute base class, I created the matrix class:

    public abstract class Matrix<T> 

    Then, I derived classes for specific numeric types from this base type:

    public class SingleMatrix : Matrix<Single> 

    Everything was coming together just fine, until I went to test the library functions. Here's some code I wrote to test the matrix multiplication function:

    SingleMatrix smA = new SingleMatrix(new float[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); 
    SingleMatrix smB = new SingleMatrix(new float[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }); 
     
    SingleMatrix smC = smA * smB; 
    outputTextBox.Text = smC.ToString(); 

    However, when compiling, I get the following error:
    Cannot implicitly convert type 'MatrixMathLib.Matrix<float>' to 'MatrixMathLib.SingleMatrix'. An explicit conversion exists (are you missing a cast?)

    When I include an explicit cast, it works just fine:
    SingleMatrix smC = (SingleMatrix)(smA * smB); 

    If possible, I'd like to avoid forcing developers to cast the output each time an operation is completed...the idea behind this library is that it should be extremely simple to use and extend. Is there any code I can write which will handle this? I tried adding an implicit cast to the SingleMatrix class (cast from Matrix<float>), but I got a compilation error saying that casts to base classes are not allowed.

    Any ideas?



    EDIT: For completeness...I've included more relevant code below:

    Operator overloading in base class:

    protected abstract void Multiply(T b); 
     
    protected abstract void Multiply(Matrix<T> b); 
     
    public static Matrix<T> operator *(Matrix<T> a, T b) 
        a.Multiply(b); 
        return a; 
     
    public static Matrix<T> operator *(Matrix<T> a, Matrix<T> b) 
        a.Multiply(b); 
        return a; 



    And the header for the derived class method:

    protected override void Multiply(Matrix<float> b) 


    • Edited by profquail Thursday, September 4, 2008 3:28 PM Spelling
    Thursday, September 4, 2008 3:16 PM

Answers

  • You'll be fighting the .NET generics implementation all the way.  You cannot cast a Matrix<T> where T is float to a T something else.  You'll have to reconstruct the object from scratch, casting each individual element.  That's not just an issue with .NET generics, C++ and Java templates work the same way.  The internal memory representation of the class object is fundamentally different.  A 2 x 2 Matrix<int> takes 16 bytes, a 2 x 2 Matrix<double> takes 32 bytes.
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Tuesday, September 9, 2008 9:55 AM
    Friday, September 5, 2008 11:18 PM
    Moderator

All replies

  • The problem is that your multiplication operator returns a Matrix<T>, not a SingleMatrix.  There really isn't a way to resolve this without breaking your design... unfortunately, math and generics don't play well together.  You should consider stepping back and thinking about what generics are really offering you... why not drop the Matrix<T> class and use SingleMatrix as the base?

    A separate issue is that your operators modify one of the parameters.  You generally don't see this done because it makes the operation non-repeatable.  It's as if 2 * 2 only = 4 the first time...

    -Ryan / Kardax
    Thursday, September 4, 2008 7:04 PM
  • Well, the reason I did things this way is because most of the highly optimized matrix math libraries have special routines for each type of data (byte, short, int, long, float, double), and I wanted to be able to offer a generic interface for them to be able to plug into. For those data types, I derived ByteMatrix, Int16Matrix, Int32Matrix, Int64Matrix, SingleMatrix and DoubleMatrix. I was also hoping to define casts for the derived matrix classes (so that, for example, a SingleMatrix could be cast/converted to a DoubleMatrix if necessary). Of all of the matrix libraries I've come across, this is (well, would be) the simplest interface I've ever used.

    If I can solve this problem, everything else should fall into place nicely.

    I'm also planning to make static "worker" classes that will take in a Matrix<T>, perform some row/column/scalar operations on the generic matrices, and output the result. This would make adding new features quite easy by simply deriving and extending another static class from this interface.


    As for part 2, the operators modify one of the parameters, but they are called by static wrapper functions, i.e.:

    SingleMatrix c = a * b;

    Neither a nor b is changed here, only copies are passed to the operator functions. (Unless I'm missing something, that is).
    Friday, September 5, 2008 12:37 AM
  • You'll be fighting the .NET generics implementation all the way.  You cannot cast a Matrix<T> where T is float to a T something else.  You'll have to reconstruct the object from scratch, casting each individual element.  That's not just an issue with .NET generics, C++ and Java templates work the same way.  The internal memory representation of the class object is fundamentally different.  A 2 x 2 Matrix<int> takes 16 bytes, a 2 x 2 Matrix<double> takes 32 bytes.
    Hans Passant.
    • Marked as answer by Zhi-Xin Ye Tuesday, September 9, 2008 9:55 AM
    Friday, September 5, 2008 11:18 PM
    Moderator