Generic constraint to match numeric types
In this case you want to constrain your generic to the IComparable
interface, which gives you access to the CompareTo
method, since this interface allows you to answer the question ShouldBeGreaterThan
.
Numeric types will implement that interface and the fact that it also works on strings shouldn't bother you that much.
Is there a constraint that restricts my generic method to numeric types?
C# does not support this. Hejlsberg has described the reasons for not implementing the feature in an interview with Bruce Eckel:
And it's not clear that the added complexity is worth the small yield that you get. If something you want to do is not directly supported in the constraint system, you can do it with a factory pattern. You could have a
Matrix<T>
, for example, and in thatMatrix
you would like to define a dot product method. That of course that means you ultimately need to understand how to multiply twoT
s, but you can't say that as a constraint, at least not ifT
isint
,double
, orfloat
. But what you could do is have yourMatrix
take as an argument aCalculator<T>
, and inCalculator<T>
, have a method calledmultiply
. You go implement that and you pass it to theMatrix
.
However, this leads to fairly convoluted code, where the user has to supply their own Calculator<T>
implementation, for each T
that they want to use. As long as it doesn’t have to be extensible, i.e. if you just want to support a fixed number of types, such as int
and double
, you can get away with a relatively simple interface:
var mat = new Matrix<int>(w, h);
(Minimal implementation in a GitHub Gist.)
However, as soon as you want the user to be able to supply their own, custom types, you need to open up this implementation so that the user can supply their own Calculator
instances. For instance, to instantiate a matrix that uses a custom decimal floating point implementation, DFP
, you’d have to write this code:
var mat = new Matrix<DFP>(DfpCalculator.Instance, w, h);
… and implement all the members for DfpCalculator : ICalculator<DFP>
.
An alternative, which unfortunately shares the same limitations, is to work with policy classes, as discussed in Sergey Shandar’s answer.
Limit a generic type argument only to be a numeric type
No, there is still no generic type constraint for a "numeric" type.
To get your T a = 0
specifically you can just use T a = default(T)
. The default of all numeric types is 0.
How to write a generic function that accepts any numerical type?
Go 1.18
With the introduction of type parameters in Go 1.18, this is easier to accomplish.
You can define a function parametrized in T
and use an interface constraint to restrict T
to numeric types.
func add[T Number](a, b T) T {
return a + b
}
The constraint Number
can be defined using golang.org/x/exp/constraints
package (still experimental):
import "golang.org/x/exp/constraints"
type Number interface {
constraints.Integer | constraints.Float
}
Where:
Number
is the union of the type sets ofconstraints.Integer
andconstraints.Float
constraints.Integer
is the set of all signed and unsigned integer typescontraints.Float
is the set of float types
This will allow you to call add
with any two arguments of numeric type. Then in the function body you will be able to use any operation that is supported by all types in the constraint. So in case of numbers, this includes also arithmetic operators. Then declaring similar functions is easy:
func multiply[T Number](a, b T) T {
return a * b
}
Keep in mind that the arguments must have the same type. Regardless of generics, you can't use different types; from the specs Operators:
[...] the operand types must be identical unless the operation involves shifts or untyped constants.
Therefore our generic add
and multiply
functions are defined with only one type parameter T
. This implies that you also can't call the add
function with untyped constants whose default types are incompatible:
add(2.5, 2) // won't compile
In this case the compiler will infer the type of T
from the first argument 2.5
, which defaults to float64
, and then won't be able to match the type of 2
, which defaults to int
.
Full program:
package main
import (
"fmt"
"golang.org/x/exp/constraints"
)
type Number interface {
constraints.Integer | constraints.Float
}
func main() {
a := 1
b := 2
fmt.Println(add(1, 2)) // 3
fmt.Println(add(a, b)) // 3
fmt.Println(add(1.5, 3.2)) // 4.7
// fmt.Println(add(2.5, 2)) // default type int of 2 does not match inferred type float64 for T
}
func add[T Number](a, b T) T {
return a + b
}
Playground: https://go.dev/play/p/rdqi3_-EdHp
Generic type constraint for numerical type only
You can specify type constraints (using both classes and protocols) for a generic class (same syntax applies to functions) using angle brackets:
class Foo<T: Equatable, U: Comparable> { }
To specify more than one requirement on a single type, use a where
clause:
class Foo<T: UIViewController where T: UITableViewDataSource, T: UITextFieldDelegate> { }
However, it doesn't look like you can specify optional requirements in a generic parameter clause, so one possible solution is to create a protocol that all the numeric types implement via extensions and then constrain your class on that requirement:
protocol Numeric { }
extension Float: Numeric {}
extension Double: Numeric {}
extension Int: Numeric {}
class NumberCruncher<C1: Numeric> {
func echo(num: C1)-> C1 {
return num
}
}
NumberCruncher<Int>().echo(42)
NumberCruncher<Float>().echo(3.14)
Generic constrain for bitwise operators
Generics are about allowing any Random class that any Programmer on the planet might throw in for T. However the numeric types are actually a very static list. I would never expect a programmer to make his own numeric type. Stuff with a overloaded Operators including binary ones? Maybe rarely.
So this is very much not a generic case. If you only write code for 2 - maybe 3 - types you should cover just about every generic in existence:
- the highest range integer you have to expect signed Int64 IIRC
- the highest range floating point you have to expect. IIRC, Decimal*.
- optionally BigInteger, for when you have to expect really big numbers. However a short look revealed that none of Math class functions support BigInt values. They keep it to Decimal, Double and many smaler built in Numerics. So this case might have been dropped as to rare and to easy to get wrong.
*Correction: While Decimal has the highest amount of digits of precision and bigest size at 64 bit, Double has the bigger range. By an order of Magnitude, that itself has an order of Magnitude.
Generics - where T is a number?
What version of .NET are you using? If you are using .NET 3.5, then I have a generic operators implementation in MiscUtil (free etc).
This has methods like T Add<T>(T x, T y)
, and other variants for arithmetic on different types (like DateTime + TimeSpan
).
Additionally, this works for all the inbuilt, lifted and bespoke operators, and caches the delegate for performance.
Some additional background on why this is tricky is here.
You may also want to know that dynamic
(4.0) sort-of solves this issue indirectly too - i.e.
dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect
Re the comment about <
/ >
- you don't actually need operators for this; you just need:
T x = ..., T y = ...
int c = Comparer<T>.Default.Compare(x,y);
if(c < 0) {
// x < y
} else if (c > 0) {
// x > y
}
Any elegant way to operate with generic types?
If Eric ever reads this,
If you want something brought to my attention, try the contact link on my blog. Or put my full name in the text of the question so that me searching for myself will find me.
does this feature (constraining generic types by defined operators) ever come up in hypothetical future versions of C# design meetings and has it ever been close to making it into the language?
Indeed, this is a frequently requested feature. We've been getting requests for this sort of thing since C# 1.0.
The feature would requires support from the CLR team, not just the language -- it is the sort of feature that we would want to integrate into all our languages, which increases the cost.
The CLR team has expressed interest in features like this, but they also have a lot of competing features that they could be doing, and limited time and effort to implement those features.
There are numerous ways such a feature could be implemented. For example, we could add the ability to specify static methods in interfaces:
interface IAddable<T>
{
static T operator+(T x, T y);
}
and then
static T Sum<T>(IEnumerable<T> seq) where T : IAddable<T>
{
T sum = default(T);
foreach(T item in seq) sum = sum + item;
return sum;
}
The idea would be that the interface means "a type that implements this interface must have the given static methods". We'd then make int automatically implement IAddable<int>
, and so on.
How do do so efficiently in a world with runtime-generated generic code is an open question.
I hasten to add that this is just a sketch of an idea. There are many ways to implement this sort of feature. The "statics in interfaces" idea is one that has broader usage than just mathematics, and that's attractive to us. If we're going to go to the huge expense of this sort of feature, it would be nice to have a really general, powerful feature rather than one narrowly focussed on math.
On the other hand, the perfect is the enemy of the good; it might be better to just concentrate on the math problem and not go for a more expensive general solution.
It's an ongoing debate. It is definitely on everyone's radar screen, but I would not expect it any time soon. The language designers are all heads-down working on going through the feedback from the async CTP.
As always, Eric's musings about hypothetical future language features of hypothetical unannounced future products are for entertainment purposes only.
Generics that restricts the types to Int, Double, long
This is not possible currently.
Also, see this question for a possible workaround
Related Topics
How to Get Rendered HTML (Processed by JavaScript) in Webbrowser Control
Adding Your Own HTMLhelper in ASP.NET MVC 3
Kanji Characters from Webclient HTML Different from Actual Kanji in Website
Can Itextsharp.Xmlworker Render Embedded Images
How to Edit CSS Style of a Div Using C# in .Net
How to Write Programs in C# .Net, to Run Them on Linux/Wine/Mono
Programmatically Rename Open File on Windows
System.Speech in Mono on Linux
Call Ruby or Python API in C# .Net
Difference Between Registerstartupscript and Registerclientscriptblock
Open Image from File, Then Release Lock
Getfiles with Multiple Extensions
C# Using Reflection to Copy Base Class Properties
How to Correctly Cast a Class to an Abstract Class When Using Type Generics