0

I have the following piece of code:

public interface IVector<T>
{
    static abstract int Length { get; }
    ref T this[int index] { get; }
}

public static class VectorExtensions
{
    public static TElement LengthSquared<TVector, TElement>(this TVector vector)
        where TVector : IVector<TElement>
        where TElement : INumberBase<TElement>
    {
        TElement lengthSquared = TElement.Zero;

        for (int i = 0; i < TVector.Length; ++i)
        {
            lengthSquared += vector[i] * vector[i];
        }

        return lengthSquared;
    }

    public static TElement Length<TVector, TElement>(this TVector vector)
        where TVector : IVector<TElement>
        where TElement : INumberBase<TElement>, IRootFunctions<TElement>
    {
        return TElement.Sqrt(vector.LengthSquared());
    }
}

Which sadly produces the following error in the second method:

The type arguments for method 'VectorExtensions.LengthSquared<TVector, TElement>(TVector)' cannot be inferred from the usage.

Is there a way to structure this code so that it can infer the type of TElement?

Rick de Water
  • 2,388
  • 3
  • 19
  • 37

1 Answers1

1

AFAIK C# always struggled a little bit with type inference for multiple generic type parameters, so you need either to specify them explicitly:

return TElement.Sqrt(vector.LengthSquared<TVector, TElement>());

Or add second parameter of TElement to LengthSquared:

public static TElement LengthSquared<TVector, TElement>(
    this TVector vector, 
    TElement _) // some parameter to infer type
    where TVector : IVector<TElement>
    where TElement : INumberBase<TElement>
{
    TElement lengthSquared = TElement.Zero;

    for (int i = 0; i < TVector.Length; ++i)
    {
        lengthSquared += vector[i] * vector[i];
    }

    return lengthSquared;
}

public static TElement Length<TVector, TElement>(this TVector vector)
    where TVector : IVector<TElement>
    where TElement : INumberBase<TElement>, IRootFunctions<TElement>
{
    return TElement.Sqrt(vector.LengthSquared(TElement.Zero));
}
Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • 1
    Better yet, remove the `TVector` type and just use `this IVector` – juharr Aug 01 '22 at 14:21
  • @juharr code uses static `TVector.Length` so unless there would instance counterpart then it can't be done. – Guru Stron Aug 01 '22 at 14:27
  • 1
    @JohnathanBarclay it does not help as far as I can see. – Guru Stron Aug 01 '22 at 14:33
  • Having the length of a Vector be static also doesn't make much sense. – juharr Aug 01 '22 at 15:52
  • @juharr it depends. I would say that it can make sense for stuff like `Vector3`, `Vector4`, ... – Guru Stron Aug 01 '22 at 15:57
  • 1
    Still wouldn't need to be static as you'd just define it as `public int Length => 3;` or `public int Length => 4;` you'd only need it to be static if you wanted to get the length of a type without creating an instance and that doesn't seem very useful. – juharr Aug 01 '22 at 16:33