Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arithmetic constraints to generic types #3333

Closed
corbane opened this issue Apr 4, 2020 · 5 comments
Closed

Arithmetic constraints to generic types #3333

corbane opened this issue Apr 4, 2020 · 5 comments

Comments

@corbane
Copy link

corbane commented Apr 4, 2020

This proposal wants to unify the type of numerical data by adding an arithmetic constraint to the generic types.

There are many arithmetic operations that have the same implementation for each type of number.

We can see it, for example, in a geometry library.
Matrix, MatrixF and MatrixD implement the same code.

With these arithmetic constraints we can define operations in external class

static class Calculator<T> where T : numeral
{
    public static T DoSomething  ( T a, T b )
    {
        return -(a + b);
    }
}

The numerical type T must define the unary and binary arithmetic operators

class VectorF
{
    public float X { get; }
    public float Y { get; }
    public VectorF ( float x, float y ) { X = x; Y = y; }
    public static VectorF operator +( VectorF a ) => new VectorF ( X, Y );
    public static VectorF operator -( VectorF a ) => new VectorF ( -X, -Y );
    public static VectorF operator ++( VectorF a ) { ++X; Y += Y/X; return this; }
    public static VectorF operator ++( VectorF a ) { --X; Y -= Y/X; return this; }
    public static VectorF operator +( VectorF a, VectorF b ) => new VectorF ( a.X + b.X, a.Y + b.Y );
    public static VectorF operator -( VectorF a, VectorF b ) => new VectorF ( a.X - b.X, a.Y - b.Y );
    public static VectorF operator *( VectorF a, VectorF b ) => new VectorF ( a.X * b.X, a.Y * b.Y );
    public static VectorF operator /( VectorF a, VectorF b ) => new VectorF ( a.X / b.X, a.Y / b.Y );
}

Calculator<VectorF>.DoSomething ( new VectorF ( -1, 0 ), new VectorF ( 0, 1 ) );

Constraint solvers (numeric or geometric) also require a lot of identical code for arithmetic operations.
Commonly, this library wraps the value inside a class.

class Param { double Value; }

Ideally, the double and Param types should be interchangeable.
In practice, there are many operators to overload.
It might be better to have a constraint on operator groups.

class SolverEngine <T> where T : arithmetic logical equality
{
    // something
}
class ParamD
{
    public double value { get; }
    public static Param operator +( Param a, Param b ) => new Param ( a.Value + b.Value );
    // other operators
}
var integerEngine = new SolverEngine <int> ();
var paramEngine = new SolverEngine <Param> ();
@333fred
Copy link
Member

333fred commented Apr 4, 2020

Did you see #1711? That is way we're looking at potentially solving this problem space.

@corbane
Copy link
Author

corbane commented Apr 4, 2020

I admit that I don't understand the #1711.
Here it is just simple and practical. Being able to put operator constraints.

@HaloFour
Copy link
Contributor

HaloFour commented Apr 4, 2020

@corbane

Unfortunately while the syntax is seemingly simple there is no facility in the runtime to actually support it. The runtime is limited to constraints of base classes and interfaces (as well as parameterless constructors, which don't apply here). There's no way to specify that a constraint should be an "operator", especially since operators are very different things depending on the type in question. For int the + operator is an IL opcode. For decimal it is a static method call. Even if you could limit it to static method calls there's no way in the runtime today to call a static method on a generic type parameter.

I'm not arguing against the feature, I would like to see it added in one form or another as well.

@corbane
Copy link
Author

corbane commented Apr 4, 2020

I have no doubt about the complexity of the implementation.
And yes, like everything, there are limits.
for example, there is no guarantee that Solver <int> and Solver <double> will work in exactly the same way, even if it shares the same arithmetic operators.
because the floating point in C # can be infinite or NaN and not integers.
But the developer has always had the task of checking types and divisions by zero.
However, being able to use a class instance as a number would be great ..

You know the peculiarities of C# much better than I do, and I think you have understood the usefulness of this proposal.
I trust you for the future of the dotnet.

@YairHalberstadt
Copy link
Contributor

Closing as being considered as part of #1711 and duplicate of #1532

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants