missing return in closure expectet to return 'Void?' - swift

I have a problem that I can't understand, I have completion handler that returns Void?
_ completionHandler: #escaping ((Int) -> Void?)
and when I use it like this:
service.getItems({ val in
row.hidden = Condition.init(booleanLiteral: val == 0)
row.evaluateHidden()
})
xCode is showing an
Missing return in a closure expected to return 'Void?'
so I have to add
return nil
What is more, if I have only 1 line in closure I dont need to return (I'm assuming it treats that 1 line as return). Whats the point of returning nil in closure that returns nullable void? Is this a bug or some kind of swift feature I don't undertand?

You need to remove the optional value for Void
This
#escaping ((Int) -> Void)
or
#escaping ((Int) -> ())
in place of
#escaping ((Int) -> Void?)

In your closure a return type is specified (here it is Optional Void Void?), thus the compiler will always expect a return value as the outcome of the function or closure.
Since this is an optional Void Void? you still have to either return nil or return Void. In function/closure with return type of non optional Void (same as no return type f.e. here:
func returnVoid() { /* do something */ }
you do not have to write the return keyword explicitly, however compiler inserts it into the function anyway.
And yes, starting with Swift 5.1 you can omit the return keyword when there is only one expression. (Source)
As for your case, you could just change your completion handler to:
_ completionHandler: #escaping ((Int) -> Void)
or the equivalent _ completionHandler: #escaping ((Int) -> ())
Optional Void Void? as the return type in your case seems not necessary.

Related

Converting non-escaping value to 'Any' may allow it to escape error - within not escaping function

My question is derived from the following Japanese question.
It's not my question, but I'm trying to answer the following problem but I cannot find the suitable answer.
https://teratail.com/questions/298998
The question above will be simpled like below.
func executetwice(operation:() -> Void) {
print(operation)
operation()
}
This compiler required to add #escaping keyword after operation: label, such as
func executetwice(operation: #escaping () -> Void) {
print(operation)
operation()
}
But in fact, it seems that operation block does not escape from this block.
Another way,
func executetwice(operation:() -> Void) {
let f = operation as Any
operation()
}
also compiler requires to add #escaping keyword. It is just upcasting to Any.
In other case, just casting to same type, it seems to be error.
func executetwice(operation:() -> Void) {
let f = operation as () -> Void //Converting non-escaping value to '() -> Void' may allow it to escape
operation()
}
I'm not sure why I need to add #escaping keyword with no escaping condition.
Just adding #escaping keyword will be Ok, but I would like to know why the compiler required the keyword in this case.
print accepts (a variable number of) Any as arguments, so that is why it's saying that you are converting a closure to Any when you pass it to print.
Many checks are applied on closure-typed parameters to make sure a non-escaping closure don't escape (for what it means for a closure to "escape", read this):
var c: (() -> Void)?
func f(operation:() -> Void) {
c = operation // compiler can detect that operation escapes here, and produces an error
}
However, these checks are only applied on closure types. If you cast a closure to Any, the closure loses its closure type, and the compiler can't check for whether it escapes or not. Let's suppose the compiler allowed you to cast a non-escaping closure to Any, and you passed it to g below:
var c: Any?
func g(operation: Any) {
// the compiler doesn't know that "operation" is a closure!
// You have successfully made a non-escaping closure escape!
c = operation
}
Therefore, the compiler is designed to be conservative and treats "casting to Any" as "making a closure escape".
But we are sure that print doesn't escape the closure, so we can use withoutActuallyEscaping:
func executetwice(operation:() -> Void) {
withoutActuallyEscaping(operation) {
print($0)
}
operation()
}
Casting a closure to its own type also makes the closure escape. This is because operation as () -> Void is a "rather complex" expression producing a value of type () -> Void. And by "rather complex" I mean it is complex enough that when passing that to a non-escaping parameter, the compiler doesn't bother to check whether what you are casting really is non-escaping, so it assumes that all casts are escaping.

How does typecasting/polymorphism work with this nested, closure type in Swift?

I know that (Int) -> Void can't be typecasted to (Any) -> Void:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler <<<< ERROR
This gives:
error: cannot convert value of type '(Int) -> Void' to specified type
'(Any) -> Void'
Question: But I don't know why this work?
let intResolver: ((Int) -> Void) -> Void = { f in
f(5)
}
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Void = intResolver
I messed around with the return type and it still works...:
let intResolver: ((Int) -> Void) -> String = { f in
f(5)
return "I want to return some string here."
}
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Any = intResolver (or stringResolver)
Sorry if this is asked before. I couldn't find this kind of question yet, maybe I don't know the keyword here.
Please enlighten me!
If you want to try: https://iswift.org/playground?wZgwi3&v=3
It's all about variance and Swift closures.
Swift is covariant in respect to closure return type, and contra-variant in respect to its arguments. This makes closures having the same return type or a more specific one, and same arguments or less specific, to be compatible.
Thus (Arg1) -> Res1 can be assigned to (Arg2) -> Res2 if Res1: Res2 and Arg2: Arg1.
To express this, let's tweak a little bit the first closure:
import Foundation
let nsErrorHandler: (CustomStringConvertible) -> NSError = { _ in
return NSError(domain: "", code: 0, userInfo: nil)
}
var anyHandler: (Int) -> Error = nsErrorHandler
The above code works because Int conforms to CustomStringConvertible, while NSError conforms to Error. Any would've also work instead of Error as it's even more generic.
Now that we established that, let's see what happens in your two blocks of code.
The first block tries to assign a more specific argument closure to a less specific one, and this doesn't follow the variance rules, thus it doesn't compile.
How about the second block of code? We are in a similar scenario as in the first block: closures with one argument.
we know that String, or Void, is more specific that Any, so we can use it as return value
(Int) -> Void is more specific than (Any) -> Void (closure variance rules), so we can use it as argument
The closure variance is respected, thus intResolver and stringResolver are a compatible match for anyResolver. This sounds a little bit counter-intuitive, but still the compile rules are followed, and this allows the assignment.
Things complicate however if we want to use closures as generic arguments, the variance rules no longer apply, and this due to the fact that Swift generics (with few exceptions) are invariant in respect to their type: MyGenericType<B> can't be assigned to MyGenericType<A> even if B: A. The exceptions are standard library structs, like Optional and Array.
First, let's consider exactly why your first example is illegal:
let intHandler: (Int) -> Void = { i in
print(i)
}
var anyHandler: (Any) -> Void = intHandler
// error: Cannot convert value of type '(Int) -> Void' to specified type '(Any) -> Void'
An (Any) -> Void is a function that can deal with any input; an (Int) -> Void is a function that can only deal with Int input. Therefore it follows that we cannot treat an Int-taking function as a function that can deal with anything, because it can't. What if we called anyHandler with a String?
What about the other way around? This is legal:
let anyHandler: (Any) -> Void = { i in
print(i)
}
var intHandler: (Int) -> Void = anyHandler
Why? Because we can treat a function that deals with anything as a function that can deal with Int, because if it can deal with anything, by definition it must be able to deal with Int.
So we've established that we can treat an (Any) -> Void as an (Int) -> Void. Let's look at your second example:
let intResolver: ((Int) -> Void) -> Void = { f in
f(5)
}
var anyResolver: ((Any) -> Void) -> Void = intResolver
Why can we treat a ((Int) -> Void) -> Void as an ((Any) -> Void) -> Void? In other words, why when calling anyResolver can we forward an (Any) -> Void argument onto an (Int) -> Void parameter? Well, as we've already found out, we can treat an (Any) -> Void as an (Int) -> Void, thus it's legal.
The same logic applies for your example with ((String) -> Void) -> Void:
let stringResolver: ((String) -> Void) -> Void = { f in
f("wth")
}
var anyResolver: ((Any) -> Void) -> Void = stringResolver
When calling anyResolver, we can pass an (Any) -> Void to it, which then gets passed onto stringResolver which takes a (String) -> Void. And a function that can deal with anything is also a function that deals with strings, thus it's legal.
Playing about with the return types works:
let intResolver: ((Int) -> Void) -> String = { f in
f(5)
return "I want to return some string here."
}
var anyResolver: ((Any) -> Void) -> Any = intResolver
Because intResolver says it returns a String, and anyResolver says it returns Any; well a string is Any, so it's legal.

Escaping Closures in Swift

I'm new to Swift and I was reading the manual when I came across escaping closures. I didn't get the manual's description at all. Could someone please explain to me what escaping closures are in Swift in simple terms.
Consider this class:
class A {
var closure: (() -> Void)?
func someMethod(closure: #escaping () -> Void) {
self.closure = closure
}
}
someMethod assigns the closure passed in, to a property in the class.
Now here comes another class:
class B {
var number = 0
var a: A = A()
func anotherMethod() {
a.someMethod { self.number = 10 }
}
}
If I call anotherMethod, the closure { self.number = 10 } will be stored in the instance of A. Since self is captured in the closure, the instance of A will also hold a strong reference to it.
That's basically an example of an escaped closure!
You are probably wondering, "what? So where did the closure escaped from, and to?"
The closure escapes from the scope of the method, to the scope of the class. And it can be called later, even on another thread! This could cause problems if not handled properly.
By default, Swift doesn't allow closures to escape. You have to add #escaping to the closure type to tell the compiler "Please allow this closure to escape". If we remove #escaping:
class A {
var closure: (() -> Void)?
func someMethod(closure: () -> Void) {
}
}
and try to write self.closure = closure, it doesn't compile!
I am going in a more simpler way.
Consider this example:
func testFunctionWithNonescapingClosure(closure:() -> Void) {
closure()
}
The above is a non-escaping closure because the closure is
invoked before the method returns.
Consider the same example with an asynchoronous operation:
func testFunctionWithEscapingClosure(closure:#escaping () -> Void) {
DispatchQueue.main.async {
closure()
}
}
The above example contains an escaping closure because the closure invocation may happen after the function returns due to the asynchronous operation.
var completionHandlers: [() -> Void] = []
func testFunctionWithEscapingClosure(closure: #escaping () -> Void) {
completionHandlers.append(closure)
}
In the above case you can easily realize the closure is moving outside
body of the function so it needs to be an escaping closure.
Escaping and non escaping closure were added for compiler optimization in Swift 3. You can search for the advantages of nonescaping closure.
I find this website very helpful on that matter
Simple explanation would be:
If a closure is passed as an argument to a function and it is invoked
after the function returns, the closure is escaping.
Read more at the link I passed above! :)
By default the closures are non escaping. For simple understanding you can consider non_escaping closures as local closure(just like local variables) and escaping as global closure (just like global variables). It means once we come out from the method body the scope of the non_escaping closure is lost. But in the case of escaping closure, the memory retained the closure int the memory.
***Simply we use escaping closure when we call the closure inside any async task in the method, or method returns before calling the closure.
Non_escaping closure: -
func add(num1: Int, num2: Int, completion: ((Int) -> (Void))) -> Int {
DispatchQueue.global(qos: .background).async {
print("Background")
completion(num1 + num2) // Error: Closure use of non-escaping parameter 'completion' may allow it to escape
}
return num1
}
override func viewDidLoad() {
super.viewDidLoad()
let ans = add(num1: 12, num2: 22, completion: { (number) in
print("Inside Closure")
print(number)
})
print("Ans = \(ans)")
initialSetup()
}
Since it is non_escaping closure its scope will be lost once we come out the from the 'add' method. completion(num1 + num2) will never call.
Escaping closure:-
func add(num1: Int, num2: Int, completion: #escaping((Int) -> (Void))) -> Int {
DispatchQueue.global(qos: .background).async {
print("Background")
completion(num1 + num2)
}
return num1
}
Even if the method return (i.e., we come out of the method scope) the closure will be called.enter code here
Swift 4.1
From Language Reference: Attributes of The Swift Programming Language (Swift 4.1)
Apple explains the attribute escaping clearly.
Apply this attribute to a parameter’s type in a method or function declaration to indicate that the parameter’s value can be stored for later execution. This means that the value is allowed to outlive the lifetime of the call. Function type parameters with the escaping type attribute require explicit use of self. for properties or methods. For an example of how to use the escaping attribute, see Escaping Closures
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: #escaping () -> Void) {
completionHandlers.append(completionHandler)
}
The someFunctionWithEscapingClosure(_:) function takes a closure as its argument and adds it to an array that’s declared outside the function. If you didn’t mark the parameter of this function with #escaping, you would get a compile-time error.
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. When you declare a function that takes a closure as one of its parameters, you can write #escaping before the parameter’s type to indicate that the closure is allowed to escape.
Definition of Escape
Swift’s closures are reference types, which means if you point two variables at the same closure they share that closure – Swift just remembers that there are two things relying on it by incrementing its reference count.
When a closure gets passed into a function to be used, Swift needs to know whether that function will get used immediately or whether it will be saved for use later on. If it’s used immediately, the compiler can skip adding one to its reference count because the closure will be run straight away then forgotten about. But if it’s used later – or even might be used later – Swift needs to add one to its reference count so that it won’t accidentally be destroyed.
Quick Example
A good example of an escaping closure is a completion handler. It’s executed in the future, when a lengthy task completes, so it outlives the function it was created in. Another example is asynchronous programming: a closure that’s executed asynchronously always escapes its original context.
public func responseData(
queue: DispatchQueue? = nil,
completionHandler: #escaping (DataResponse<Data>) -> Void)
-> Self
{
...
Extra Information
For performance reasons, Swift assumes all closures are nonescaping closures, which means they will be used immediately inside the function and not stored, which in turn means Swift doesn’t touch the reference count. If this isn’t the case – if you take any measure to store the closure – then Swift will force you to mark it as #escaping so that the reference count must be changed.
non-escaping(#noescape) vs escaping(#escaping) closure
[Function and closure]
non-escaping closure
#noescape is a closure which is passed into a function and which is called before the function returns
A good example of non-escaping closure is Array sort function - sorted(by: (Element, Element) -> Bool). This closure is called during executing a sort calculations.
History: #noescape was introduced in Swift 2 -> was deprecated in Swift 3 where became a default that is why you should mark #escaping attribute explicitly.
func foo(_ nonEscapingClosure: () -> Void) {
nonEscapingClosure()
}
escaping closure
escaping closure(reference) is alive when method was finished.
//If you have next error
Escaping closure captures non-escaping parameter
//`#escaping` to the rescue
#escaping is a closure which is
passed into a function
The owner function saves this closure in a property
closure is called(using property) after the owner function returns(async)
A good example of an escaping closure is a completion handler in asynchronous operation. If you do not mark you function with #escaping in this case you get compile time error. Reference to property in an escaping closure requires you to use self explicitly
class MyClass {
var completionHandler: (() -> Void)?
func foo(_ escapingClosure: #escaping () -> Void) {
//if you don't mark as #escaping you get
//Assigning non-escaping parameter 'escapingClosure' to an #escaping closure
completionHandler = escapingClosure //<- error here
}
func onEvent() {
completionHandler?()
}
}
completion is a completionHandlerAbout, if you want to highlight that it is #escaping you can use completionHandler naming
func foo(completion: () -> Void) {
//
}
func foo(completionHandler: #escaping () -> Void) {
//
}
[Sync vs Async]
[Java functional interfaces]
Here simple example of escaping and no escaping closures.
Non-Scaping Closures
class NonEscapingClosure {
func performAddition() {
print("Process3")
addition(10, 10) { result in
print("Process4")
print(result)
}
print("Process5")
}
func addition(_ a: Int, _ b: Int, completion: (_ result: Int) -> Void) {
print("Process1")
completion(a + b)
print("Process2")
}}
Creating an instance and calling function calling
let instance = NonEscapingClosure()
instance.performAddition()
Output:
Process3
Process1
Process4
20
Process2
Process5
And Escaping Closures
class EscapingClosure {
func performAddition() {
print("Process4")
addition(10, 10) { result in
print(result)
}
print("Process5")
}
func addition(_ a: Int, _ b: Int, completion: #escaping (_ result: Int) -> Void) {
print("Process1")
let add = a + b
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
print("Process2")
completion(add)
}
print("Process3")
}}
Creating an instance and function calling
let instance = EscapingClosure()
instance.performAddition()
Output
Process4
Process1
Process3
Process5
Process2
20

What is the syntax for a closure argument in swift

In Swift headers, the isSeparator: argument accepts a closure
public func split(maxSplit: Int = default, allowEmptySlices: Bool = default, #noescape isSeparator: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.SubSequence]
But in the documentation, it lists closure syntax differently
{ (parameters) -> return type in
statements
}
How are you supposed to know that (Self.Generator.Element) throws -> Bool rethrows refers to a closure / requires a closure? Are there other ways that the headers/docs might list argument as meaning a closure?
The "thing" giving away that this is a closure is the ->. The full type is
(Self.Generator.Element) throws -> Bool
It means that the closure takes a variable of type Self.Generator.Element and has to return a Bool upon some calculation based on the input. It may additionally throw some error while doing so - that is what the throws is for.
What you then write
{ (parameters) -> return type in
statements
}
would be an actual implementation, a value of some generic closure type.
The type of a closure is for example (someInt:Int, someDouble:Double) -> String:
var a : ((someInt:Int, someDouble:Double) -> String)
Once again the thing giving away that a is actually a closure is the -> in the type declaration.
Then you assign something to a via some code snippet following your second code block:
a = { (integer, floating) -> String in
return "\(integer) \(floating)"
}
You can tell by the argument's type. Everything in Swift has a type, including functions and closures.
For example, this function...
func add(a: Int, to b: Int) -> Int { return a + b }
...has type (Int, Int) -> Int. (It takes two Ints as parameters, and returns an Int.)
And this closure...
let identity: Int -> Int = { $0 }
...has type Int -> Int.
Every function and closure has a type, and in the type signature there is always a -> that separates the parameters from the return value. So anytime you see a parameter (like isSeparator) that has a -> in it, you know that the parameter expects a closure.
the isSeparator definition means (Self.Generator.Element) throws -> Bool that you will be given an Element and you should return a Bool. When you will call split, you then can do the following :
[1,2,3].split(…, isSeparator : { element -> Bool in
return false
})
This is a pure silly example but that illustrates the second part of your question

'Cannot convert the expression's type' with optional in closure body

I have come across (most definitely) a feature that I don't quite understand. I have a closure, that takes in a Float and has no return value, aka (number: Float) -> Void. In that closure, I perform a call on optional value, not forcing its unwrapping, because I like the behavior since the optional is a delegate (= if it's nil, don't do anything).
But when I do that, I get an error:
Cannot convert the expression's type '...' to type Float.
Interestingly enough, when I simply add println(), the error disappears. I have simplified my case to tiny little example for illustration:
var optional: [String : Int]?
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
//println() <-- when this gets uncommented, error disappears
}
My bet would be that the compiler maybe doesn't like that in some cases I'm not handling the float number, but since I am not returning the value then it should just disappear right? What am I missing?
An expression containing a single expression is inferred to return that result, hence:
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
}
is equivalent to:
let closure: (number: Int) -> Void = { (number) -> Void in
return optional?.updateValue(number, forKey: "key")
}
You now have conflicting return types between Void and Int? (remember, updateValue returns the old value)
Splitting it up with an explicit return clarifies the inferred typing.
let closure: (number: Int) -> Void = { (number) -> Void in
optional?.updateValue(number, forKey: "key")
return
}
I think your closure won't like returning nil because Void can't be converted to nil.
If you do that in a playground:
var n: Void = ()
n = nil
You'll get this error:
error: type 'Void' does not conform to protocol 'NilLiteralConvertible'