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.
#1. Using FloatingPoint protocol as a parameter generic constraint
The 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
#2. Using AdditiveArithmetic protocol as a parameter generic constraint
AdditiveArithmetic 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
#3. Using Numeric protocol as a parameter generic constraint
Numeric 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.
I think this is what you need:
You need to explicitly create a new protocol and extend the types you want (Int, Float, Double) to conform to the protocol. Than in your generic declaration you do
func addition<T: protocolJustCreated>(nr1: T, nr2: T) -> T {}
Read the answer I linked for a more complete answer. No need to repeat here.
Sqrt() and pow() both specify their parameters as either double or float. In order to meet your goal of using this one function for Int, Float, and Double you will need to also make generics of sqrt() and pow() functions.
Related
I have a closure defined like this,
public var onLogCompletion:((_ printLog:String,_ fileName:String,_ functionName:String,_ lineNumber:Int) -> ())? = nil
Which is updated like this,
fileprivate func printerCompletion(printLog:String, fileName:String, functionName: String, lineNumber:Int) -> Void {
if onLogCompletion != nil {
onLogCompletion!(printLog, getFileName(name: fileName), functionName, lineNumber)
}
}
And using it like this,
Printer.log.onLogCompletion = { (log) in
//print(log)
//print(log.0)
}
Error:
Cannot assign value of type '(_) -> ()' to type '((String, String, String, Int) -> ())?'
But this is giving me above error and not sure what to do?
The same is working fine with Swift 3.x.
The reason its not working in Swift 4 is because of Distinguish between single-tuple and multiple-argument function types(SE-0110).
If you still want to work in a way you are doing in Swift 3 than you need to set the function type's argument list to enclosed with Double parentheses like this.
public var onLogCompletion:(((String,String,String,Int)) -> ())? = nil
Now you all set to go
Printer.log.onLogCompletion = { (log) in
//print(log)
//print(log.0)
}
The code below was working in previous versions of Swift, now compiler rejects it.
I need this function to interop with Swift from ObjectiveC.
#objc public static func myFunc(jdUT: Double, _ lon: Double, _ lat: Double,
_ dayLen: Double, _ SbhDeg: Double, _ MgrbDeg: Double,
omsk: UnsafeMutablePointer<Double>)
{
var z = somefuncion()
// this line gives this error : Cannot assign to property: 'omsk' is a 'let' constant
omsk.memory=z;
}
The error message is misleading. The memory property of
Unsafe(Mutable)Pointer has been renamed to pointee in Swift 3:
let z = someFunction()
omsk.pointee = z
#objc public static func myFunc(jdUT: Double, _ lon: Double, _ lat: Double,
_ dayLen: Double, _ SbhDeg: Double, _ MgrbDeg: Double,
inout omsk: UnsafeMutablePointer<Double>)
{
var z = somefuncion()
// this line gives this error : Cannot assign to property: 'omsk' is a 'let' constant
omsk.memory=z;
}
Adding inout before the omsk parameter should work.
In swift 2.2, We could mutate a struct or enum within a closure, when it was inside a mutating function. But in swift 3.0 its no longer possible. I get the following error
closure cannot implicitly captured a mutating self parameter
Here is a code snippet,
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
test { (a) -> Void in
// Get the Error in the below line.
self.x = Double(a)
}
}
mutating func test(myClosure: #escaping (_ a: Double) -> Void) {
myClosure(3)
}
}
I get that value types are not supposed to be mutable. I have cases, where I do have to modify one variable in the struct within one of the functions, when I receive the API response. (In the completion closure)
Is what I was doing in swift 2.2, impossible or is there way to accomplish this?
The problem is that #escaping closures can be stored for later execution:
Escaping Closures
A closure is said to escape a function when the closure is passed as an argument to the function, but is called after the function returns. ...
One way that a closure can escape is by being stored in a variable that is defined outside the function....
Since the closure can be stored and live outside the scope of the function, the struct/enum inside the closure (self) will be copied (it is a value) as a parameter of the closure. And, if it was allowed to mutate, the closure could have an old copy of it, causing unwanted results.
So, in answer to your question, you cannot; unless you are able to remove "#escaping" (not your case because it's a 3rd party API)
Yeah, you can do something like this.
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
test { (a) -> Void in
self.x = Double(a)
}
}
mutating func test(myClosure: (_ a: Double) -> Void) {
myClosure(3)
}
}
Struct is value type. So when use as Model or ModelView, you can make up a closure with new Value to VC.
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
test { [x, y](a) -> Point in
// Get the Error in the below line.
return Point(x: Double(a), y: y)
}
}
mutating func test(myClosure: #escaping (_ a: Double) -> Point) {
self = myClosure(3)
}
}
I am trying to reduce an array of Bools by applying the logical operator OR (||) using the following code, however I get an error:
func reduceBools(values: [Bool]) -> Bool {
return values.reduce(false, combine: ||)
}
Ambiguous reference to member '||'
Analogously for integers the code works like a charm.
func reduceInts(values: [Int]) -> Int {
return values.reduce(0, combine: +)
}
I was able to make it work by adding a || function (code below) or using a { $0 || $1 } closure but I dislike these approaches and I would prefer simply passing the operator.
func ||(lhs: Bool, rhs: Bool) -> Bool {
return lhs || rhs
}
The same thing happens for the logical AND (&&) operator.
How can I make it work without using the hack above?
As an alternative, you could use the following approach
// ||
func reduceBoolsOr(values: [Bool]) -> Bool {
return values.contains(true)
}
// &&
func reduceBoolsAnd(values: [Bool]) -> Bool {
return !values.contains(false)
}
Note that .reduce comes with an overhead. If the end result is the importance of your question (rather than enquiring above the unexpected behaviour of || and && operators in this context), then perhaps the pragmatic approach above can be of help, even if it doesn't really reduce the array, however producing the same result due to the simple nature of the boolean type.
Swift 4.2+ / Xcode 10.0+
In modern versions of Swift there is allSatisfy function, which checks all elements for satisfying some rule.
In OP's case:
values.allSatisfy { $0 }
UPD:
To make this work for OR, do
!values.allSatisfy{!$0}
Thanks to Andy Weinstein
Following approach will work
values.reduce(false) { $0 || $1 }
Ambiguous reference to member '||' means, that there are more than one possible candidates, from which compiler is not able to choose. In your case those are
public func ||<T : BooleanType, U : BooleanType>(lhs: T, #autoclosure rhs: () throws -> U) rethrows -> Bool
and
public func ||<T : BooleanType>(lhs: T, #autoclosure rhs: () throws -> Bool) rethrows -> Bool
probably your 'hack' using a { $0 || $1 } is the best solutions here.
This happens because of Swifts closure semantics. It takes your arguments and applies function to them, omitting argument names.
protocol Numeric {
...
public static func +(lhs: Self, rhs: Self) -> Self
...
}
In example with Ints, you would pass (Int, Int) into a closure, and + function in Numeric protocol expects exactly two ints to sum them.
Thats why code like below works just fine
[1, 2, 3, 4].reduce(0, +)
Because you just took 2 ints, and applied function, which takes just two ints.
If you write your own function, which would take just two argument, it would work as well.
func myOwnAwesomeFunc<T: Numeric>(a: T, b: T) -> T { in
return 1 // production ready
}
[1, 2, 3, 4].reduce(0, myOwnAwesomeFunc) // prints 1
Good so far. But why can't we write
[true, false, true].reduce(false, ||) // yields Cannot invoke 'reduce'
// with an argument list of type
// '(Bool, (Bool, #autoclosure () throws -> Bool) throws -> Bool)'
That's because this operator takes bool and a closure, which returns bool. Not bool, closure!
But if it is like this, why aren't we writing true || { false }() ?
Thats because of #autoclosure, which takes care of curly braces for us.
Main question, why is it implemented this way, so we can't use Swifts awesome short-hand closure syntax with booleans? Idk
Here's another approach, I modified the reduceBools function to take the operator as a parameter -
typealias LogicalOperator = ((Bool, #autoclosure () throws -> Bool) throws -> Bool)
func reduceBools(values: [Bool], combine: LogicalOperator) -> Bool {
var started: Bool = false
return values.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value // obviously up to you how you'd handle the try/catch
started = true
})
}
let bools = [true, false, false, true]
let result1 = self.reduceBools(values: bools, combine: ||)
print(result1) // prints true
let result2 = self.reduceBools(values: bools, combine: &&)
print(result2) // prints false
Or it could be more useful as an extension of Sequence -
extension Sequence where Element == Bool {
func reduce(_ combine: LogicalOperator) -> Bool {
var started: Bool = false
return self.reduce(into: true, { (result, value) in
result = started ? try! combine(result, value) : value
started = true
})
}
}
print(bools.reduce(||)) // prints true
I am playing around with the custom operator >>> for function composition that is suggested here.
I have defined the following:
infix operator >>> { associativity left }
func >>> <A, B, C>(f: B -> C, g: A -> B) -> (A -> C) {
return { x in f(g(x)) }
}
func toChars(s: String) -> [Character] {
return s.characters.reduce([]) { (acc, c) in acc + [c] }
}
func myReverse(xs: [Character]) -> String {
if let (head, tail) = xs.decompose {
return String(myReverse(tail)) + String(head)
}
return ""
}
Now, when I want to put together those two functions like this:
func reverseString(s: String) -> String {
return myReverse >>> toChars
}
I am getting the compiler error:
Cannot convert value of type ([Character]) -> String to expected
argument type _ -> _.
According to my understanding this should work. >>> is defined to take two functions f : B -> C and g : A -> B. Looking at the structure of my usage, the following becomes clear:
g in this case is toChar : String -> [Character], so A is String and B is [Character]
f in this case is myReverse : [Character] -> String, so B is [Character] and C is String
This matches the type definitions form above, however I am still getting a compiler error. Does anyone know what I am doing wrong? Is there a syntax issue with the code?
Note, I am using an Array extension where the function decompose is defined like so:
var decompose : (head: Element, tail: [Element])? {
if count > 0 {
return (self[0], Array(self[1..<count]))
}
return nil
}
myReverse >>> toChars returns a closure of type String -> String,
you still have to call the closure with a string argument:
func reverseString(s: String) -> String {
return (myReverse >>> toChars)(s)
}
But what you probably want is:
let reverseString = myReverse >>> toChars
In both cases, reverseString has the type String -> String,
so you can call it as
print(reverseString("foo"))
// oof