Compile error when a lazy variable handle error in the catch block

Environment: Swift and XCode 7 beta 5 (7A176x) under OSX 10.10


If a declare a lazy variable that catches an error then XCode produces the compile error "call can throw, but it is not marked with 'try' and the error is not handled" but the damned error is handled!!!


The offending code


class LazyBug {
    lazy var catchHandleError : String = {
        do {
            let list = try NSFileManager.defaultManager().contentsOfDirectoryAtPath("/")
            if list.count > 0 {
                return list[0]
            }
        } catch let error as NSError {
            return "error"
        }
        return ""
    }()
}


If the catch statement is empty the code compiles as shown below


class LazyBug {
    lazy var catchIsEmpty : String = {
        do {
            let list = try NSFileManager.defaultManager().contentsOfDirectoryAtPath("/")
            if list.count > 0 {
                return list[0]
            }
        } catch {
        }
        return ""
    }()
}


I think this behaviour is incorrect, is this a bug?

Accepted Reply

If you want to use do-catch in a block, you need to pretend exaustive catches, as in your second code.

class LazyBug {
    lazy var catchHandleError : String = {
        do {
            let list = try NSFileManager.defaultManager().contentsOfDirectoryAtPath("/")
            if list.count > 0 {
                return list[0]
            }
        } catch let error as NSError {
            return "error"
        } catch {
            return "unknown error"
        }
        return ""
        }()
}

Replies

Such sort of behavior is found when do-catch exists in a block:

var operation = NSBlockOperation {
    do {
        let url = NSURL(fileURLWithPath: "/Users/dev/Desktop/test.txt")
        let data = try NSData(contentsOfURL: url, options: [])
    } catch {
    }
}
operation = NSBlockOperation { //error: cannot invoke initializer for type 'NSBlockOperation' with an argument list of type '(() throws -> ())'
    do {
        let url = NSURL(fileURLWithPath: "/Users/dev/Desktop/test.txt")
        let data = try NSData(contentsOfURL: url, options: [])
    } catch let error as NSError {
    }
}

It is said that catch should be exaustive like switch-cases.

But such errors are not generated when we write do-catch in a non-throws method.

class LazyBug {
    class func CatchingMethod() -> String {
        do {
            let list = try NSFileManager.defaultManager().contentsOfDirectoryAtPath("/")
            if list.count > 0 {
                return list[0]
            }
        } catch let error as NSError {
            return "error"
        }
        return ""
    }
    lazy var catchHandleError : String = LazyBug.CatchingMethod()
}


I haven't found a clear explanation about the differece between two cases.

Ok creating a separated class fixes the problem but I should prefer if swift can use the catch in lazy methods, too

If you want to use do-catch in a block, you need to pretend exaustive catches, as in your second code.

class LazyBug {
    lazy var catchHandleError : String = {
        do {
            let list = try NSFileManager.defaultManager().contentsOfDirectoryAtPath("/")
            if list.count > 0 {
                return list[0]
            }
        } catch let error as NSError {
            return "error"
        } catch {
            return "unknown error"
        }
        return ""
        }()
}

The 'exaustive' approach is perfect for me and very coherent with the language idioms, thanks!!!

`Exhaustive` looks like a right spelling..., sorry for my bad English. Anyway I'm glad to hear you found your issue solved. Good luck and may your app be great.