How to declare a local variable that is a closure in swift - swift

I want to declare a local variable which is of type closure how do I do that?

var myClosure: (myParamaterTypes) -> myReturnTypes
eg:
var myClosure: (Int, Int) -> Int // type is (Int, Int) -> Int
myClosure = {(integer01: Int, integer02: Int) -> Int in return integer01 + integer02}

Related

Distinguishing Tuple and Multi-Argument Functions

I write this function in playground which has value parameter of tuple type and return type is tuple.
func tuple(value: (Int, Int) ) -> (first: Int, second: Int) {
let firstGrabTuple = value.0 + 5
let secondGrabTuple = value.1 + 5
return (firstGrabTuple, secondGrabTuple)
}
Then I assigned it to constant called closure
let closure = tuple
//(Playground showing) let closure became a function of type (Int, Int) -> (first: Int, second: Int)
Then for double check I write another function that takes closure as its parameter, of type ((Int, Int)) -> (Int, Int)
func anotherTuple(_ closure: ((Int, Int)) -> (Int, Int)) {
closure((5, 5))
}
when I call anotherTuple
anotherTuple { (x) -> (Int, Int) in
let first = x.0 + 5
let second = x.1 + 5
return (first, second)
}
//prints .0 10, .1 10 as expected
So My question is as mention above when first function tuple I assigned it to constant called closure became of type (Int, Int) -> (first: Int, second: Int). But in second function If i have to use a parameter of type as tuple I have to set its parameter in double parentheses like (_ closure: ((Int, Int)) -> (Int, Int)).
But If I remove those double parentheses from anotherTuple function parameter then it will only expect 2 values as multi-argument function. No error for used as multi-argument function instead of tuple argument why is that? Added image for more detail.
and second question is why that
let closure = tuple
//let closure became a function of type (Int, Int) -> (first: Int, second: Int)
not became of type ((Int, Int)) -> (first: Int, second: Int)
**Note - When I tried to pass that constant named closure as argument to another function which will expect closure of type ((Int, Int)) -> (Int, Int) then while typing closure showing me it as ((Int, Int)) -> (Int, Int) in auto complete code.
You're correct about the confusion. I'm somewhat going to just restate your understanding, and say "yes, tuples in Swift are weird and slightly broken."
Swift does not distinguish between functions that take tuples vs multiple arguments in some ways, but does distinguish in other ways. (This is one of many reasons to avoid tuples at this point in Swift's life.)
First, these two functions have almost the same type in Swift (note that Void and () are identical):
func tuple(value: (Int, Int) ) {} // (Int, Int) -> Void
func two(value1: Int, value2: Int) {} // (Int, Int) -> Void
They look the same. But if you define a function that accepts that type, it can't take tuple:
func take(f: (Int, Int) -> Void) {}
take(f: tuple) // Fails
take(f: two) // ok
But if you define a function that takes ((Int, Int)) -> Void it can accept either function:
func take(f: ((Int, Int)) -> Void) {}
take(f: tuple) // ok
take(f: two) // ok
That suggests that (Int, Int) -> Void is a subtype of ((Int, Int)) -> Void.
But variables belie this:
var f: (Int, Int) -> Void
f = tuple // Ok
f = two // Ok
var g: ((Int, Int)) -> Void
g = tuple // ok
g = two // ok
g = f // ok
f = g // ok
And that suggests that (Int, Int) -> Void and ((Int, Int)) -> Void are the same type. But the take function indicates they're not.
Yes. All of that is true at the same time. Functions that accept tuples are not a coherent type in Swift (they do not occupy a clearly-deliniated spot in the type hierarchy). That's just where we are in Swift today.
Old, incorrect answer.
This is just a quirk of Playgrounds, and you should feel free to open a radar about that.
If you check type(of: closure), it'll print the type you expect. Swift knows the correct type; Playgrounds just displays the wrong thing.

unexpected non-void return value in void function

Below is my code. I'm learning closures. I'm getting an error that my function would not return a value. Can someone help?
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) {
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)
Use this modified code as you have missed return type in the function ( -> Int)
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int{
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)

Weird escaping function behavior after updating to Swift 3

I'm having difficulties with the following lines of code after updating to Swift 3:
private var functionHandlers = [(() -> Int) -> ()]()
private var myFunction: (() -> Int)?
func doRegister() {
functionHandlers.append { (f: (() -> Int)) in
myFunction = f
}
}
That gave me the compiler error: Assigning non-escaping parameter 'f' to an escaping closure
So then, I tried this:
func doRegister() {
functionHandlers.append { (f: #escaping (() -> Int)) in
myFunction = f
}
}
and this:
func doRegister() {
functionHandlers.append { (f: (#escaping () -> Int)) in
myFunction = f
}
}
which, in both cases, fixed my first error, but then gave me a new compiler error: Cannot convert value of type '(#escaping (() -> Int)) -> ()' to expected argument type '(() -> Int) -> ()'
So then I tried changing the type of functionHandlers as follows:
private var functionHandlers = [(#escaping (() -> Int)) -> ()]()
but that just resulted in a syntax error.
Can anyone explain to me why this is happening and what I can do to fix this?
Looks like a bug to me. For some reason, the compiler doesn't like the syntax:
private var functionHandlers = [(#escaping () -> Int) -> ()]()
but it does like:
private var functionHandlers : [(#escaping () -> Int) -> ()] = []
It's the same symptom, but I'm unsure it's the same cause as the compiler rejecting the [TypeA.TypeB]() syntax with nested types. Although like that problem, another way of solving it is by using a typealias:
typealias F = (#escaping () -> Int) -> ()
private var functionHandlers = [F]()
You can then implement doRegister() as you correctly tried to implement it as:
func doRegister() {
functionHandlers.append { (f: #escaping () -> Int) in
myFunction = f
}
}
Although you should certainly file a bug report over [(#escaping () -> Int) -> ()]() not compiling.

Cannot convert return expression type to return type with closure?

Hello i have some func for pagination messages.
class func listMessages() -> (Int, Int, ([ChatItemProtocol]) -> Void) {
let service = MessageService()
func list(count: Int, offset: Int, comp:([ChatItemProtocol]) -> Void) {
let params : [String : AnyObject] = ["offset" : offset, "limit" : count]
service.listMessagesForRoom(params) { (messages) in
comp(messages.map({$0}))
}
}
return list
}
and i have some error :
Cannot convert return expression of type '(Int, offset: Int, comp: ([ChatItemProtocol]) -> Void) -> ()' to return type '(Int, Int, ([ChatItemProtocol]) -> Void)' (aka '(Int, Int, Array<ChatItemProtocol> -> ())')
listMessages(...) expects the following tuple return type
(Int, Int, ([ChatItemProtocol]) -> Void)
The function list(...), on the other hand, uses the above as argument but will implicitly also contain a Void (/empty tuple type ()) return type. I.e., the full signature for list(...) is
(Int, Int, ([ChatItemProtocol]) -> Void) -> ()
leading to a type mis-match when you attempt to return list as the return value of listMessages(...).
Without knowing the purpose of your code, it is difficult to give any concrete advice, but you could fix the above by modifying the return type of listMessages(...) to include also the () return type, in so matching the signature of list(...)
class func listMessages() -> ((Int, Int, ([ChatItemProtocol]) -> Void) -> ())

Swift enum that has associated values, got "missing argument label 'array' in call"

I'm learning Swift. Below is my code:
enum MyTest
{
case Point(Int, Int)
case What(String)
case GiveMeFunc((array: Int...) -> Int)
}
var p1 = MyTest.Point(2, 2)
var p2 = MyTest.Point(3, 3)
var s1 = MyTest.What("Haha...")
var s2 = MyTest.What("Heihei...")
var f1 = MyTest.GiveMeFunc({(array: Int...) -> Int in return 8})
var f2 = MyTest.GiveMeFunc({(array: Int...) -> Int in return 9})
switch p1 {
case .What(let string):
println(string)
case .GiveMeFunc(let f):
println(f(1, 2, 4, 3))
case .Point(let a, let b):
println("a: \(a) b: \(b)")
}
When I run it I got
missing argument label 'array' in call.
The error comes from :
println(f(1, 2, 4, 3))`
How to fix the error?
By inserting the array: label:
case .GiveMeFunc(let f):
println(f(array: 1, 2, 4, 3))
since the definition of the function requires it:
case GiveMeFunc((array: Int...) -> Int)
Alternatively if you redefined GiveMeFunc to not have a named argument, you wouldn't have to supply it:
case GiveMeFunc((Int...) -> Int)
As you can see in the error message: missing argument label 'array' in call
If you look at your closure GiveMeFunc((array: Int...) -> Int) it takes a parameter called array
So the error message is saying that you're missing that parametername
So by doing: println(f(array: 1, 2, 4, 3)) it works
Or changing the closure to GiveMeFunc((Int...) -> Int)