Assume we have idea for generic class Matrix<T>
where T
is numeric type (Complex
or double
or float
, int
etc).
It is natural that we have implicit conversions in C# from float
to double
, from double
to Complex
. General rule is that we have implicit conversion from smaller type to bigger type. So far so good.
Now imagine we are implementing our Matrix<T>
type. Since this new type in a way is numeric also (or at least it holds numeric values) it is only natural to have implicit conversions from Matrix<float>
to Matrix<double>
, from Matrix<double>
to Matrix<Complex>
etc. At least it is nice to have these for mathematical operations like multiply, add etc. However this seems impossible to implement correctly because implicit operator requires that at least one type is the same as class we are implementing it in.
Example: below code doesn't compile even thought it could resolve my problem.
public abstract partial class Matrix<T>
{
/// <summary>
/// Implicitly converts a matrix to double precision complex numbers.
/// </summary>
public static implicit operator Matrix<Complex64>(Matrix<double> matrix)
{
matrix.ToComplex();
}
/// <summary>
/// Implicitly converts a matrix to double precision real numbers.
/// </summary>
public static implicit operator Matrix<double>(Matrix<float> matrix)
{
matrix.ToDouble();
}
}
It will not compile because "CS0556 User-defined conversion must convert to or from the enclosing type" and let's say I'm fine with that because it is part of the language specification but shouldn't there be any other way to achieve this?
For example this doesn't compile either.
public abstract partial class Matrix<double>
{
/// <summary>
/// Implicitly converts a matrix to single precision real numbers.
/// </summary>
public static implicit operator Matrix<double>(Matrix<float> matrix)
{
matrix.ToDouble();
}
}
Is there any way to achieve this thing, it feels natural so I think it should be achievable?
For now I have created a workaround which enables implicit conversion for all types to biggest one but that doesn't resolve conversion from Matrix<float>
to Matrix<double>
, it only resolves conversions to Matrix<Complex>
.
public abstract partial class Matrix<T>
{
/// <summary>
/// Implicitly converts a matrix to double precision complex numbers.
/// </summary>
public static implicit operator Matrix<Complex64>(Matrix<T> matrix)
{
return matrix.Map(x =>
{
if (x is Numerics.Complex32)
{
var xc32 = (Numerics.Complex32)(object)x;
return new Complex64(xc32.Real, xc32.Imaginary);
}
return new Complex64(Convert.ToDouble(x), 0);
}, Zeros.AllowSkip);
}
}
If anyone is interested in background around this problem, you may take a look at https://github.com/mathnet/mathnet-numerics/issues/304
Another option to resolve this could be to use something like "extension operators" (similar to extension methods) but those are not present in C#.