I have this function that is going to calculate the hypotenuse from 2 numbers
func hypotenusa<T>(nr1: T, nr2: T) -> T {
return sqrt( pow(nr1, 2) + pow(nr2, 2) )
}
// v Simpler situation v
func addition<T>(nr1: T, nr2: T) -> T {
return nr1 + nr2
}
I want to use generics so I don't have to make 3 copies of this which uses Int, Float, Double separately
But this isn't working, I think generics is really difficult to work with, please help me :)
Swift generics aren't like C++ templates.
In C++, you can just try to use a parameterized type however you want, and it's not an error until the compiler tries to instantiate the template with some type that doesn't support what your template tries to do.
In Swift, the generic construct can only use a parameterized type in ways known to be valid when the generic construct is first parsed. You specify these "ways known to be valid" by constraining the parameterized type with protocols.
You cannot call sqrt
or pow
with generic-typed arguments, because those functions are not themselves generic. They have each two definitions:
func pow(_: Double, _: Double) -> Double
func pow(lhs: Float, rhs: Float) -> Float
func sqrt(x: Double) -> Double
func sqrt(x: Float) -> Float
You could write type-specific versions of hypotenusa
:
func hypotenusa(a: Float, b: Float) -> Float
func hypotenusa(a: Double, b: Double) -> Double
func hypotenusa(a: CGFloat, b: CGFloat) -> CGFloat
I'm not sure why you'd create an Int
version at all, since very few right triangles have integer hypotenuses.
Anyway, you don't need to define the Float
and Double
versions at all, because the standard library already provides a hypot
function defined on Float
and Double
:
func hypot(_: Double, _: Double) -> Double
func hypot(lhs: Float, rhs: Float) -> Float
You could create another override for CGFloat
:
func hypot(l: CGFloat, r: CGFloat) -> CGFloat {
return hypot(Double(l), Double(r))
}
As for your addition
function, it has the same problem as your hypotenusa
function: the +
operator is not defined entirely generically. It has some generic definitions (unlike sqrt
and pow
), but those only cover the integer types (see IntegerArithmeticType
). There's not generic definition of +
that covers the floating-point types. Swift defines all of these versions of +
with explicit types:
func +(lhs: Float, rhs: Float) -> Float
func +<T>(lhs: Int, rhs: UnsafePointer<T>) -> UnsafePointer<T>
func +<T>(lhs: UnsafePointer<T>, rhs: Int) -> UnsafePointer<T>
func +(lhs: Int, rhs: Int) -> Int
func +(lhs: UInt, rhs: UInt) -> UInt
func +(lhs: Int64, rhs: Int64) -> Int64
func +(lhs: UInt64, rhs: UInt64) -> UInt64
func +<T>(lhs: Int, rhs: UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
func +<T>(lhs: UnsafeMutablePointer<T>, rhs: Int) -> UnsafeMutablePointer<T>
func +(lhs: Int32, rhs: Int32) -> Int32
func +(lhs: UInt32, rhs: UInt32) -> UInt32
func +(lhs: Int16, rhs: Int16) -> Int16
func +(lhs: UInt16, rhs: UInt16) -> UInt16
func +(lhs: Int8, rhs: Int8) -> Int8
func +(lhs: UInt8, rhs: UInt8) -> UInt8
func +(lhs: Double, rhs: Double) -> Double
func +(lhs: String, rhs: String) -> String
func +(lhs: Float80, rhs: Float80) -> Float80
With Swift 5, according to your needs, you can pick one of the following ways in order to solve your problem.
FloatingPoint
protocol as a parameter generic constraintThe Apple Developer Documentation for FloatingPoint
shows the following hypotenuse
function implementation as an example of FloatingPoint
usage:
func hypotenuse<T: FloatingPoint>(_ a: T, _ b: T) -> T {
return (a * a + b * b).squareRoot()
}
let (dx, dy) = (3.0, 4.0)
let result = hypotenuse(dx, dy)
print(result) // prints: 5.0
AdditiveArithmetic
protocol as a parameter generic constraintAdditiveArithmetic
has the following declaration:
A type with values that support addition and subtraction.
The Playground sample code below shows a possible usage of AdditiveArithmetic
as a function parameter generic constraint:
func addition<T: AdditiveArithmetic>(a: T, b: T) -> T {
return a + b
}
let result = addition(a: 3, b: 4)
print(result) // prints: 7
Numeric
protocol as a parameter generic constraintNumeric
has the following declaration:
A type with values that support multiplication.
The Playground sample code below shows a possible usage of Numeric
as a function parameter generic constraint:
func multiply<T: Numeric>(a: T, b: T, c: T) -> T {
return a * b * c
}
let result = multiply(a: 3, b: 4, c: 5)
print(result) // prints: 60
Note that Numeric
protocol inherit from AdditiveArithmetic
protocol.
The Apple Developer Documentation contains a dedicated page for all numeric protocols: Numeric Protocols.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With