Need help with generic vector math

I'm trying to create a Vector type with generic math approach.
//my vector class
public readonly struct Vec2<TScalar>(TScalar x, TScalar y) :
IVector<Vec2<TScalar>, TScalar>
where TScalar : INumber<TScalar>
{ ... }

//my interface
public interface IVector<TSelf, TScalar> : IVector<TScalar>,
IAdditiveIdentity<TSelf, TSelf>,
IMultiplicativeIdentity<TSelf, TScalar>,
IAdditionOperators<TSelf, TSelf, TSelf>,
ISubtractionOperators<TSelf, TSelf, TSelf>,
IMultiplyOperators<TSelf, TScalar, TSelf>,
IDivisionOperators<TSelf, TScalar, TSelf>,
IUnaryNegationOperators<TSelf, TSelf>,
IUnaryPlusOperators<TSelf, TSelf>,
IEqualityOperators<TSelf, TSelf, bool>,
IEquatable<TSelf>
where TSelf : IVector<TSelf, TScalar>
where TScalar : INumber<TScalar>
{
static abstract int Rank { get; }
TScalar this[int axis] { get; }

public static virtual TScalar Dot(TSelf a, TSelf b)
{
TScalar val = TScalar.Zero;
for (int i = 0; i < TSelf.Rank; i++)
{
val += a[i] * b[i];
}
return val;
}
}

//my extension method
public static TScalar Dot<TVec, TScalar>(this TVec a, TVec b)
where TVec : IVector<TVec, TScalar>
where TScalar : INumber<TScalar>
{
return TVec.Dot(a, b);
}

//my test code
Vec2<float> a = new(1, 2);
var x = a.Dot(a);//error here, said cs0411: The type arguments for method 'method' cannot be inferred from the usage
//my vector class
public readonly struct Vec2<TScalar>(TScalar x, TScalar y) :
IVector<Vec2<TScalar>, TScalar>
where TScalar : INumber<TScalar>
{ ... }

//my interface
public interface IVector<TSelf, TScalar> : IVector<TScalar>,
IAdditiveIdentity<TSelf, TSelf>,
IMultiplicativeIdentity<TSelf, TScalar>,
IAdditionOperators<TSelf, TSelf, TSelf>,
ISubtractionOperators<TSelf, TSelf, TSelf>,
IMultiplyOperators<TSelf, TScalar, TSelf>,
IDivisionOperators<TSelf, TScalar, TSelf>,
IUnaryNegationOperators<TSelf, TSelf>,
IUnaryPlusOperators<TSelf, TSelf>,
IEqualityOperators<TSelf, TSelf, bool>,
IEquatable<TSelf>
where TSelf : IVector<TSelf, TScalar>
where TScalar : INumber<TScalar>
{
static abstract int Rank { get; }
TScalar this[int axis] { get; }

public static virtual TScalar Dot(TSelf a, TSelf b)
{
TScalar val = TScalar.Zero;
for (int i = 0; i < TSelf.Rank; i++)
{
val += a[i] * b[i];
}
return val;
}
}

//my extension method
public static TScalar Dot<TVec, TScalar>(this TVec a, TVec b)
where TVec : IVector<TVec, TScalar>
where TScalar : INumber<TScalar>
{
return TVec.Dot(a, b);
}

//my test code
Vec2<float> a = new(1, 2);
var x = a.Dot(a);//error here, said cs0411: The type arguments for method 'method' cannot be inferred from the usage
So I get a error at the test code, how can I do this right?
5 Replies
Aaron
Aaron5mo ago
you have to do var x = a.Dot<Vec2<float>, float>(a); C# isn't able to use generic constraints to do inference, so it doesn't see TVec : IVector<TVec, TScalar> when trying to figure out what TScalar is
jinsediaoying
jinsediaoying5mo ago
I see the problem, but this isn't convenient at all? Is there any I can change to make such extension work, and write as less repeatative codes as possible?
Aaron
Aaron5mo ago
Is there any I can change to make such extension work
no, not that i know of besides just redefining the extension methods for every concrete IVector implementation
jinsediaoying
jinsediaoying5mo ago
That sounds pretty sad.
geo
geo5mo ago
The return type of Dot is a generic type and you haven’t specified a type anywhere. (Btw I think the solution is probably using fewer generics not more, there’s a lot going on there.)