"Missing return in a closure expected to return 'SomeType'" error in .map - swift

I have the fallowing code:
struct AInt {
var aInt: Int
}
struct ADouble {
var aDouble: Double
static func convert(aInt: AInt) throws -> ADouble {
return ADouble(aDouble: Double(aInt.aInt))
}
}
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
}
// ^^^ error here: Missing return in a closure expected to return 'ADouble'
}
}
let aInts = [AInt(aInt: 2), AInt(aInt: 3)]
let b = B()
do {
print(try b.doAction(aInts))
}
catch {}
When i'm trying to convert [AInt] to [ADouble] in .map using function that can throw error, i get this error:
Missing return in a closure expected to return 'ADouble'.
Well, i decided to add return statement in the end of .map like this:
return aInts.map { aInt in
do {
try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
Error disappear, but when i print try b.doAction(aInts) on same aInts array, i get this: [ADouble(aDouble: 2.2), ADouble(aDouble: 2.2)], i.e. it prints my ADouble(aDouble: 2.2) that i set manually. Obviously, it's not what i want, so then i try to add return before try ADouble.convert(aInt) like this:
return aInts.map { aInt in
do {
return try ADouble.convert(aInt)
}
catch {
print(error)
}
return ADouble(aDouble: 2.2)
}
And now i get right result: [ADouble(aDouble: 2.0), ADouble(aDouble: 3.0)]. But this code still doesn't work without return statement in the end of the .map. Any ideas how to get rid of it?

The map() method is declared as
#rethrows public func map<T>(#noescape transform: (Self.Generator.Element) throws -> T) rethrows -> [T]
which means (if I understand it correctly) that the transform can
either return a value or throw an error (and this will be
forwarded to the caller).
This compiles and works as expected:
struct B {
func doAction(aInts: [AInt]) throws -> [ADouble] {
return try aInts.map { aInt in
return try ADouble.convert(aInt)
}
}
}
An error thrown from ADouble.convert(aInt) will be forwarded to
the caller of map() and from there to the caller of doAction().

Related

How to get the string I put into a Error instance?

Basicly I got this,
// MyPackage.swift
enum Error: LocalizedError {
case general(String)
}
func foobar() throws {
throw Error.general("haha")
}
do {
try foobar()
} catch Error.general(let message) {
// will print "haha"
print(message)
}
And then in the unit test, I need to check if I got the exact same error,
import Quick
import Nimble
import MyPackage
class MySpec: QuickSpec {
override func spec() {
describe("") {
let input = "haha"
let count = 2
let expectation = Error.general("非纯数字字符串无法使用本方法")
context("输入_" + input) {
it("预期_" + expectation.localizedDescription) {
// got the error
// but expectation.localizedDescription was not what I looking for
expect(try numberStringByAddingZerosInto(input, tillReach: count))
.to(throwError(expectation))
}
}
}
}
}
It worked, but expectation.localizedDescription was not "haha", which made the name of the test case useless.
I also tried expectation.errorDescription with no luck.
Where could I get it?
And why is it like this?
override errorDescription var
enum Error: LocalizedError {
case general(String)
var errorDescription: String? {
switch self {
case .general(let errorMessage):
return errorMessage
}
}
}
Now, you can also write do-catch block by this
do {
try foobar()
} catch let error {
print(error.localizedDescription)
}

How to write a template function that handle do catch

I want to write a template function that handle do catch. It may look like this
func handleMethod(methodNeedToHandle) -> result: notSureType{
var result
do {
let response = try handleMethod
result = response
return result
} catch let error as someObjectError{
result = error
return result
}
}
Then you can use it like
let catchResult = handleMethod(method(x: something, y: something))
Thank you guys help me a lot, I get working code below
func handleDoTryCatch<T>(closure:() throws -> T) -> Any {
do {
let result = try closure()
return result
} catch let error {
return error
}
}
You could use a generic function that takes a closure and returns a tuple.
Something like:
func handle<T>(closure:() throws -> T) -> (T?, Error?) {
do {
let result = try closure()
return (result, nil)
} catch let error {
return (nil, error)
}
}
This will define a function that takes a closure that calls the method that can throw. It the returns a tuple with the expected return type and something that conforms to the Error protocol.
You would use it like this:
let result: (Void?, Error?) = handle { try someFunc() }
let result2: (Int?, Error?) = handle { try someOtherFunc(2) }
someFunc and someOtherFunc are just examples and their signatures would be:
func someFunc() throws {}
func someOtherFunc(_ param: Int) throws -> Int {}
This is the function I managed to come up with:
// Your error cases
enum Errors: Error {
case someErrorCase
}
// Function to test another function
func doTryCatch<T>(for function: () throws -> T) {
do {
let returnValue = try function()
print("Success! The return value is \(returnValue)")
} catch {
print("Error! The error reason was \"\(String(describing: error))\"")
}
}
// Function to test
func failingFunction() throws -> Int {
throw Errors.someErrorCase // <-- Comment this to not recieve an error (for testing)
return 5 // Will return 5 if the error is not thrown
// Failure: Error! The error reason was "someErrorCase"
// Success: Success! The return value is 5
}
// Perform the test
doTryCatch(for: failingFunction) // <-- Very easy to test, no closures to write!
Hope this helps with your debugging! :)
The closest I could get to what you probably want is the following:
(Swift Playground code:)
func handleMethod(_ f: #autoclosure () throws -> Void) -> Error? {
do {
try f()
} catch let err {
return err
}
return nil
}
enum HelloError: Error {
case tooShort
}
func hello(_ what: String) throws {
guard what.count > 0 else { throw HelloError.tooShort }
print ("Hello \(what)!")
}
// use like this:
// let err = handleMethod(try hello("World")) // err == nil
// let err = handleMethod(try hello("")) // err == HelloError.tooShort
//
print ("* hello(\"World\") -> \(String(describing: handleMethod(try hello("World"))))")
print ("* hello(\"\") -> \(String(describing: handleMethod(try hello(""))))")
This will produce the following output:
Hello World!
* hello("World") -> nil
* hello("") -> Optional(__lldb_expr_3.HelloError.tooShort)
Consider just using do/catch as George_E recommends. It's a good advice. But if you need this function, than this snipped hopefully gives you a starting point.

Nested do catch swift 3.0

I'd like to use consecutive try statements. If one returns an error I'd like to proceed to the next one, otherwise return the value.
The code below seems to work fine, however I'll end up with a big nested do catch pyramid. Is there a smarter/better way to do it in Swift 3.0?
do {
return try firstThing()
} catch {
do {
return try secondThing()
} catch {
return try thirdThing()
}
}
If the actual errors thrown from those function calls are not needed
then you can use try? to convert the result to an optional,
and chain the calls with the nil-coalescing operator ??.
For example:
if let result = (try? firstThing()) ?? (try? secondThing()) ?? (try? thirdThing()) {
return result
} else {
// everything failed ...
}
Or, if the error from the last method should be thrown if everything fails,
use try? for all but the last method call:
return (try? firstThing()) ?? (try? secondThing()) ?? (try thirdThing())
If Martin's answer is too terse for your taste you can just go with individual catch blocks.
do {
return try firstThing()
} catch {}
do {
return try secondThing()
} catch {}
do {
return try thirdThing()
} catch {}
return defaultThing()
As each throwing function's result is immediately returned no nesting is necessary.
Another way to do this is to write a function that takes all your throwing functions as an argument. It returns the first one that was successfully executed or nil.
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
The lazy ensures that the values are only called until it finds the first match. Doing it this way, you can also add a lot of cases very quickly.
You can use the function like this
return first(firstThing, secondThing, thirdThing) ?? "Default"
I also included the code I used to test this in playground:
enum ThingError: Error {
case zero
}
func firstThing() throws -> String {
print("0")
throw ThingError.zero
return "0"
}
func secondThing() throws -> String {
print("1")
return "1"
}
func thirdThing() throws -> String {
print("2")
return "B"
}
func first<T>(_ values: (() throws -> T)...) -> T? {
return values.lazy.flatMap({ (throwingFunc) -> T? in
return try? throwingFunc()
}).first
}
func tryThings() -> String {
return first(firstThing, secondThing, thirdThing) ?? "Default"
}
tryThings() // prints "0" and "1"

Using Do/Catch in Swift

I am working on an app and want to get data back from a function. However sometimes data is missing or is different from the kind of that I want to retrieve. I am new to Swift and I can't find a way to write a function that does a little bit of processing and returns this data. When this data is missing, the function should give back a string "Not Found". Like this:
func processData(data:String) {
do {
//processing
var result = processedData
} catch {
var result = "Not Found"
}
return result
}
It would be very nice if somebody could help me.
You should check if the result is nil.
func processData(data: String?) -> String {
guard let result = data else {
return "Not Found"
  }
return result
}
The most concise way of doing it would be using the guard-let construct:
func processData(data: String?) -> String {
// Assuming getProcessedData(:) returns your processed data
guard let result = getProcessedData(data) else {
return "Not found"
}
return result
}
Also, your function is missing a return type. You must specify the return type like -> TYPE in all functions that return some value.
Those answer were written till mine are right. There is one way: with handler check get result and use by your point.
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?, completionHandler: #escaping (_ result: String? , _ error: Error?) -> Void ) {
guard let data = data else {
// Data is missing
throw nil, Errors.noData
}
// Do other things, and throw if necessary
result = data
return result, nil
}
// example of calling this function
process(data: "A data to process"){(result, error) -> Void in
//do any stuff
/*if error == nil {
}*/
}
A good practice in swift would be to use correctly the throws errors
This is an example inspired from yours :
enum Errors: Error {
case noData
case unknownError
}
func progress(data: String?) throws -> String {
guard let data = data else {
// Data is missing
throw Errors.noData
}
// Do other things, and throw if necessary
result = data
return result
}
do {
try process(data: "A data to process")
} catch {
print("An error occurred: \(error)")
}
You can try this code as is in a Swift Playgound
Your function needs to be explicit about returning something with e.g. -> String Also do-catch is for methods that can throw an error. It seems like you need to take a look at how to use optionals. Optionals can have a value or they can have no value.
fun processData(data: String) -> String {
var result: String?
// Do some processing and assign the result to result variable
guard let result = result else { return "Not Found" }
return result
}

Why does iterating over closures cause a bus error in swift?

I'm getting a strange Bus Error when running what appears to be perfectly safe swift code. I've tried to reduce it down to a minimal test case, as follows:
Apple Swift version 2.2-dev (LLVM 3ebdbb2c7e, Clang f66c5bb67b, Swift 0ddf238ad7)
Target: x86_64-apple-macosx10.9
This code:
public enum MyError: ErrorType {
case SomeError(code: Int)
}
public typealias MyType = () throws -> Bool
public class Foo {
var a:MyType = { () throws -> Bool in
print("A")
return true
}
var b:MyType = { () throws -> Bool in
print("B")
return true
}
var c:MyType = { () throws -> Bool in
print("C")
throw MyError.SomeError(0)
}
}
public func handle<T>(test:T) {
let mirror = Mirror(reflecting: test)
print(mirror.subjectType)
for child in mirror.children {
if let callable = child.value as? MyType {
do {
try callable()
}
catch MyError.SomeError(let id) {
print(id)
}
catch {
print("unknown error")
}
}
}
}
let foo = Foo()
handle(foo)
Generates this output:
Foo
A
B
C
Bus error: 10
Running it in the debugger works fine, so I assume it has something to do with a timing issue at runtime.
Am I doing something illegal or unsafe in this code?
Are exceptions somehow illegal in closures?
What's causing this error?
Edit:
I've created a bug on the swift issue tracker for this now here: https://bugs.swift.org/browse/SR-324
What's causing this error?
The error doesn't happen until you get to the last closure:
var c:MyType = { () throws -> Bool in
print("C")
throw MyError.SomeError(0)
}
Obviously, you're throwing an exception here, and I suspect that the problem has less to do with iterating over the children and more to do with throwing an exception while you're doing that iterating. I tried calling c without iterating:
public func trythis() {
let foo = Foo()
do {
try (foo.c)()
}
catch MyError.SomeError(let id) {
print(id)
}
catch { print("unknown") }
}
trythis()
and found that it worked fine. I also tried removing the throw from c:
var c:MyType = { () throws -> Bool in
print("C")
// throw MyError.SomeError(code: 0)
return true
}
and found that the code works fine in that case. So it's the combination of throwing while iterating over the list that's the problem, and that makes me suspect that it's just a compiler bug or maybe some problem with the Mirror class.
I think you should file a bug report with Apple for this one.
I agree with Caleb that this must be a bug.
But just to be clear, it is not the combination of throwing while iterating. It is the combination of reflecting and throwing.
This is a modified version of your handle function:
public func handle<T>(test:T) {
let mirror = Mirror(reflecting: test)
print(mirror.subjectType)
// Extract only the last function, no iteration...
if let callable = mirror.children[AnyForwardIndex(2)].value as? MyType {
do {
try callable()
}
catch MyError.SomeError(let id) {
print(id)
}
catch {
print("unknown error")
}
}
}
This function will cause the same error as your function.
You simply can not call a function that throws, if found using reflection.
Bug I would say.