Generic function with binary operations
The Numeric
protocol requires addition, subtraction and multiplication operators,
but not a division operator.
I am not aware of a protocol which requires a division operator to which both integer and floating point types conform, therefore you have to
implement two overloaded functions:
func normalizeArray<T: FloatingPoint>(a: [T]) -> [T] { ... }
func normalizeArray<T: BinaryInteger>(a: [T]) -> [T] { ... }
Note that your implementation will crash if called with an empty
array, I'll suggest
func normalizeArray<T: BinaryInteger>(a: [T]) -> [T] {
guard let min = a.min(), let max = a.max() else {
return []
}
return a.map({ ($0 - min) / (max - min) })
}
Generic binary operation in a class definition?
You could use a class decorator to mutate your class and add them all in with the help of a factory function:
import operator
def natural_binary_operators(cls):
for name, op in {
'__add__': operator.add,
'__sub__': operator.sub,
'__mul__': operator.mul,
'__truediv__': operator.truediv,
'__floordiv__': operator.floordiv,
'__and__': operator.and_,
'__or__': operator.or_,
'__xor__': operator.xor
}.items():
setattr(cls, name, cls._make_binop(op))
return cls
@natural_binary_operators
class Vector(tuple):
@classmethod
def _make_binop(cls, operator):
def binop(self, other):
try:
return cls([operator(a, x) for a, x in zip(self, other)])
except:
return cls([operator(a, other) for a in self])
return binop
There are a few other ways to do this, but the general idea is still the same.
Generic constraint 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.
Binary comparison operators on generic types
Adding constraint to make sure that the type implements IComparable<T>
is a way to go. However, you cannot use the <
operator - the interface provides a method CompareTo
to do the same thing:
public class MyClass<T> where T : IComparable<T> {
public T MaxValue {
// Implimentation for MaxValue
}
public T MyMethod(T argument) {
if(argument.CompareTo(this.MaxValue) > 0){
// Then do something
}
}
}
If you needed other numeric operators than just comparison, the situation is more difficult, because you cannot add constraint to support for example +
operator and there is no corresponding interface. Some ideas about this can be found here.
Are binary operators / infix functions in R generic? And how to make use of?
Yes, this is possible: use '+.<class name>' <- function()
.
Examples
'+.product' <- function(a, b) a * b
'+.expo' <- function(a, b) a ^ b
m <- 2; class(m) <- "product"
n <- 3; class(n) <- "product"
r <- 2; class(r) <- "expo"
s <- 3; class(s) <- "expo"
m + n # gives 6
r + s # gives 8
safety notes
The new defined functions will be called if at least one of the arguments is from the corresponding class m + 4
gives you 2 * 4 = 8
and not 2 + 4 = 6
. If the classes don't match, you will get an error message (like for r + m
). So all in all, be sure that you want to establish a new function behind such basic functions like +
.
How to define generic reductions using any binary Operator example OR or AND, custom function?
The helpers sum, product, etc are not actually built-ins. They are just helpers written in the Halide front-end language itself, so you can define more if you like, or make a generic that takes a binary operator. I would start by looking at https://github.com/halide/Halide/blob/master/src/InlineReductions.cpp
The bulk of the magic is just the automatic capturing of free variables, the rest is just like the code you wrote.
Usage of arithmetic operants (+, -, /, *) with generic types
For this you need to create a new protocol
that lets Swift know any instance of T
can have numeric operators performed on it, for example:
protocol NumericType: Equatable, Comparable {
func +(lhs: Self, rhs: Self) -> Self
func -(lhs: Self, rhs: Self) -> Self
func *(lhs: Self, rhs: Self) -> Self
func /(lhs: Self, rhs: Self) -> Self
func %(lhs: Self, rhs: Self) -> Self
init(_ v: Int)
}
extension Double : NumericType {}
extension Int : NumericType {}
Source: What protocol should be adopted by a Type for a generic function to take any number type as an argument in Swift?
Now when you define your MathStatistics
class:
class MathStatistics<T: NumericType> {
var numbers = [T]()
func average() -> T? {
if numbers.count == 0 {
return nil
}
let sum = numbers.reduce(T(0)) { $0 + $1 }
return sum / T(numbers.count)
}
}
Now you can use MathsStatistics
like so:
let stats = MathStatistics<Int>()
stats.numbers = [1, 3, 5]
println(stats.average()) // Prints: Optional(3)
How do I require a generic type implement an operation like Add, Sub, Mul, or Div in a generic function?
Let's break down your example a bit:
fn cube<T: Mul>(x: T) -> T {
let a = x * x;
let b = a * x;
b
}
What are the types of a
and b
? In this case, the type of a
is <T as std::ops::Mul>::Output
— sound familiar from the error message? Then, we are trying to multiply that type by x
again, but there's no guarantee that Output
is able to be multiplied by anything!
Let's do the simplest thing and say that T * T
needs to result in a T
:
fn cube<T: Mul<Output = T>>(x: T) -> T {
x * x * x
}
Unfortunately, this gives two similar errors:
error[E0382]: use of moved value: `x`
--> src/lib.rs:6:9
|
6 | x * x * x
| - ^ value used here after move
| |
| value moved here
|
= note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
Which is because the Mul
trait takes arguments by value, so we add the Copy
so we can duplicate the values.
I also switched to the where
clause as I like it better and it is unwieldy to have that much inline:
fn cube<T>(x: T) -> T
where
T: Mul<Output = T> + Copy
{
x * x * x
}
See also:
- How do I implement the Add trait for a reference to a struct?
- How to write a trait bound for adding two references of a generic type?
Generic Constraint for allowing bitwise operations?
There is no appropriate generic type constraint for this situation. You can apply bitwise operations to int
s, so convert the enum value to int. T
cannot be cast to int
directly; however, you can make the detour over object
.
public static string ToFlags<T>(this T val)
where T : struct
{
return string.Join(",", Enum.GetValues(typeof(T))
.Cast<T>()
.Select(enumEntry => ((int)(object)enumEntry & (int)(object)val) > 0
? enumEntry.ToString() : "")
.Where(f => !string.IsNullOrWhiteSpace(f)));
}
Note: There is a similar situation with numbers. You can't say where T : number
and apply numeric operators on values of type T.
Also you can make val
a T
and you don't have to pass the type of T
as method argument. You are passing it as generic type argument already. This is sufficient. The compiler is also smart enough to infer T
, so you don't have to specify it when calling the method.
// Test
Flags item = Flags.COMMAND_ACTION | Flags.COMMAND_MSG;
Console.WriteLine(item.ToFlags());
You can specify struct
as generic type constraint, as struct
stands for value types. It is not perfect, but better than no constraint at all.
Related Topics
Saving And/Or Querying User Display Names in Firebase Using Caseinsensitive
Swift Video to Document Directory
Swift - Nsdate - Remove Part of Date
Swiftui Vertically Misaligned Text
How to Build a Recursive Function in Swift to Return a String
Swift 4 JSONdecoder Optional Variable
How to Programmatically Change The Xdr Display Reference Mode (Aka Preset) on Macos
Swift Sha256 Encryption Returns Different Encrypted String Compare to Objective C
Swiftui Navigationview Not See Image
Lldb for Swift: Access Computed Property or Perform Function Call in Type Summary Python Script
How to Set Default Clouse Param in View Method
How to List All Available Patterns in a Scdynamicstorage
Support Arkit in Lower End Devices
Firestore - Creating a Copy of a Collection