Swift: Passing in functions that throw exceptions - swift

I have the following toy example
func identity<T>(a : T) -> T{
return a
}
func applyIdentity<T>(f : T->T, t:T) -> T{
return f(t)
}
applyIdentity(identity, t:1)
And this works without a hitch. However, once I try to throw an exception in identity like so:
enum MyError: ErrorType{
case MyErrorFoo
};
func identity<T>(a : T) throws -> T{
if (true) {
return a
} else {
throw MyError.MyErrorFoo
}
}
...
The type checker complains on the applyIdentity(identity, t:1) call with message:
Argument for generic parameter 'T' could not be inferred
Any idea why this may be happening?

Your (second) identity() method can throw an error, therefore it has the type
T throws -> T, not T -> T.
If applyIdentity() should just forward
an error thrown in f() to the caller then you can define it as
func applyIdentity<T>(f : T throws ->T , t:T) rethrows -> T {
return try f(t)
}
See also "Declarations" in the Swift book:
Rethrowing Functions and Methods
A function or method can be declared with the rethrows keyword to
indicate that it throws an error only if one of it’s function
parameters throws an error. These functions and methods are known as
rethrowing functions and rethrowing methods. Rethrowing functions and
methods must have at least one throwing function parameter.

Related

Swift: Why is this call ambiguous?

Why does the following code yield an "Ambiguous use of 'foo'" compile error? I'd think that the return value makes it clear which one of the foo() overloads should be called.
Even more interestingly, why does the error disappear if I remove the print("x") line? What difference does that make?
(Xcode 10.2.1, Swift 5, default build settings for a new project.)
func foo(_: () -> Int) {}
func foo(_: () -> String) {}
func bar() {
foo() {
print("x")
return 42
}
}
Type inference only applies to single-expression closures, so the compiler doesn't attempt to infer the type of the closure based on the return expression because there are two expressions (the print and the return). It then tries to infer the return type based on the return type of the closure passed to foo, but it finds two different foos and can't decide which one to use, so it then complains of an ambiguous use of foo. If you explicitly declare the type of the closure, the following code will compile:
func bar() {
foo() { () -> Int in
print("x")
return 42
}
}

How to declare a rethrowing function?

I implemented the following function -as an extension of array of booleans- which could throw a CustomError error:
enum CustomError: Error {
case empty
case doesNotContainTrue
}
extension Array where Element == Bool {
func indexOfFirstTrue() throws -> Int {
if isEmpty { throw CustomError.empty }
guard let detectedIndex = index(of: true) else {
throw CustomError.doesNotContainTrue
}
return detectedIndex
}
}
which works as expected:
let myArray = [false, true, false, true]
try print(myArray.indexOfFirstTrue()) // 1
Next, I tried to declare a function as:
func handleResult(_ index: Int) throws {
print(index * 2)
// ...
}
which should take the result of myArray.indexOfFirstTrue() and do something with it (for simplicity, let's assume that it prints the value multiplied by 2):
try handleResult(myArray.indexOfFirstTrue()) // 2
What I want to do is to declare handleResult as rethrowing function:
A function or method can be declared with the rethrows keyword to
indicate that it throws an error only if one of its function
parameters throws an error. These functions and methods are known as
rethrowing functions and rethrowing methods. Rethrowing functions and
methods must have at least one throwing function parameter.
The Swift Programming Language (Swift 4.1): Declarations - Rethrowing Functions and Methods.
So I can call it with non-throwing formula, thus it will not throws an error:
handleResult(myArray.indexOfFirstTrue()) // 2
But I am stuck of what should I edit to let it be a rethrowing function, so I tried to declare it as:
func handleResult(_ index: Int) rethrows {
print(index * 2)
}
and I got the error of:
error: 'rethrows' function must take a throwing function argument
therefore, I also tried to declare it as:
func handleResult(_ index: (() throws -> Int)) rethrows {
print(index * 2)
}
and obviously got the error of:
error: cannot convert value of type 'Int' to expected argument type
'() throws -> Int'
What should I do at this point?
Remember, the argument is of type () -> Int! So you need to call the function passed in to get the result! You also need try since the function can throw.
func handleResult(_ index: (() throws -> Int)) rethrows {
print(try index() * 2) // see the "()"?
}
Now you can use it like this:
let myArray = [true]
try handleResult(myArray.indexOfFirstTrue)

Disambiguate a complex closure return type (foo -> _)

I'm using Alamofire's Result class. I've boiled Result down to a simple subset for presentation here.
public enum Result<Value> {
case success(Value)
case failure(Error)
}
extension Result {
/// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
public func mapError<T: Error>(_ transform: (Error) -> T) -> Result {
switch self {
case .failure(let error):
return .failure(transform(error))
case .success:
return self
}
}
}
I can't get a call to mapError to compile.
I make a simple Error class and a couple of results:
class MyError: Error { }
let s: Result<Bool> = .success(true)
let f: Result<Bool> = .failure(MyError())
Now I have something to call mapError on! Maybe I'll print any error before passing it along unchanged:
f.mapError() {
print($0)
return $0
}
Here Swift tells me "error: unable to infer complex closure return type; add explicit type to disambiguate". It doesn't seem that complex to me; mapError passes an Error into the closure, and expects one (or T:Error) returned, but I try placating Swift anyway:
f.mapError() { (e: Error)->Error in
print(e)
return e
}
Now Swift says, "error: cannot convert value of type '(Error) -> Error' to expected argument type '(Error) -> _'".
What is this _ return type? And how should I be writing the closure?
(I realize I can avoid calling mapError, but whatever, I can’t seem to call it. If I really wanted to, how would I even do so?)
You cannot pass a closure of type (Error) -> Error to mapError
because a protocol does not conform to itself, i.e. Error is not
a valid T for the constraint <T: Error>.
Making mapError non-generic
public func mapError(_ transform: (Error) -> Error) -> Result
makes both of your usage examples compile.
What is this _ return type [in the error]?
This means the compiler cannot determine a type, which might give a further clue as to what's going on...

Infer closure return type from closure body when working with generics

I think best if I start with an example:
class Test<T> {
func test(closure: (T) -> Void) { }
func test(closure: (T) -> T) { }
func test(closure: (T) -> Test<T>) { }
}
Test<Int>().test { a in }
The code above gives the following error:
error: ambiguous use of 'test'
This is because the Swift compiler doesn't know to which one of the three methods is should map the call to. But from the closure body it's quite clear that it returns a Void, so it should pick the first method.
Looks like the Swift compiler cannot determine to which method overload to map the call to based on the closure body. If I explicitly specify the closure signature, then the problem goes away:
Test<Int>().test { (a: Int) -> Void in }
My question is: can I somehow instruct Swift to pick-up the correct overload for short-hand closure expressions like the one in discussion, or will I have to explicitly declare the closure signature?
Actually, it seems that I was pushing the compiler limits too hard (as #Martin R pointed in the comments). The { a in } closure was kinda incomplete, since the compiler had no statements to infer the closure return type from.
This works:
Test<Int>().test { (a: Int) -> Void in () }
Same as the following:
func doNothing() { }
Test<Int>().test { (a: Int) -> Void in doNothing() }
In the above examples the compiler is provided with the minimum amount of information to determine which overload to pick.

Throwing an exception from an inherited function without throws

I'm trying to do the following:
protocol X{
func foo()
}
enum XError{
case BAR
}
class Y:X{
func foo(){
throw XError.BAR
}
}
I can't add a throws declaration to the protocol and it complains that
the error is not handled because the enclosing function is not
declared 'throws'.
How can I achieve this?
You need to explicitly add throw in the signature of any function that throws.
So
func foo() throws {
throw XError.BAR
}
This also applies to the protocol definition.
protocol X {
func foo() throws
}
Errors in Swift should conform to the Error protocol.
enum XError: Error {
case BAR
}