The error handler doesn't have to be co-linear or even defined in the same call:

/// consists of filename, line number, error tuple
public typealias CommonErrorHandlerType = (String, Int, ErrorType) -> Void

/// Default error handler prints context and error
public let defaultCommonErrorHandler: CommonErrorHandlerType = {
    filePath, lineNumber, error in
    let trimmedFileName: String = (filePath as NSString).lastPathComponent
    print("Error \(trimmedFileName):\(lineNumber) \(error)")
}

If you're doing much more than printing or adding a line-or-two extra then 
I don't think you should be using guard, you should be applying do-catch at the 
call site
or using try (not try? or try!) and forwarding the error handling.

-- E


> On Mar 23, 2016, at 8:05 AM, Maximilian Hünenberger <[email protected]> 
> wrote:
> 
> Your "attempt" function addresses this  issue if someone only wants to print 
> the error:
> 
> guard let x = attempt({ try throwingFunction(y) }) else {
>          return
> }
> // prints "Error \(trimmedFileName):\(lineNumber) \(error)"
> 
> In contrast to
> 
> guard let x = try? throwingFunction(y) catch {
>         // you have to make your own print
>         return
> }
> 
> ---------------------
> 
> However if you want to handle the error before you exit the scope it is quite 
> inconvenient:
> 
> guard let x = attempt({ _, _, error in /* handle error */ }, { try 
> throwingFunction(y) } ) else {
>         return
> }
> 
> In contrast to:
> 
> guard let x = try? throwingFunction(y) catch {
>         // handle error
>         return
> }
> 
> - Maximilian
> 
> Am 14.03.2016 um 18:00 schrieb Erica Sadun <[email protected] 
> <mailto:[email protected]>>:
> 
>>> On Mar 14, 2016, at 10:20 AM, Maximilian Hünenberger via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>> How about only allowing "guard try? catch":
>>> 
>>>     guard let x = try? foo() catch { ... }
>>> 
>>> This would address both concerns of Chris:
>>> 
>>> • "This is inconsistent with what we currently have, because “if let” and 
>>> “guard let” match against an optional and succeed iff the optional is 
>>> present."
>>> 
>>> • "This shouldn’t be tied to the presence of try, because it already means 
>>> something (that the enclosed expression can throw).  This:
>>>         guard let x = try foo() …
>>> Already means “call foo, if it throws, propagate the error.  If not, test 
>>> the returned optional”."
>>> 
>>> 
>>> With "try?" it is clear that "foo()" doesn't throw an error in the guard 
>>> expression and guard matches against an optional. This makes it unambiguous 
>>> to "guard try else" which throws in this case.
>>> 
>>> Kind regards
>>> - Maximilian
>> 
>> 
>> 
>> I'm not a fan of the notion of guard/catch. However, it occurs to me that my 
>> "attempt" code may address this issue.
>> I've recently updated it to take an arbitrary error handler, which if 
>> omitted, simply prints the error. Otherwise it acts like try?
>> or if you set crashOnError, like try!. It works with guard.
>> 
>> -- E
>> 
>> github: 
>> https://github.com/erica/SwiftUtility/blob/master/Sources/CoreError.swift 
>> <https://github.com/erica/SwiftUtility/blob/master/Sources/CoreError.swift>
>> 
>> public typealias CommonErrorHandlerType = (String, Int, ErrorType) -> Void
>> 
>> /// Replacement for `try?` that introduces an error handler
>> /// The default handler prints an error before returning nil
>> ///
>> /// - Parameter file: source file, derived from `__FILE__` context literal
>> /// - Parameter line: source line, derived from `__LINE__` context literal
>> /// - Parameter crashOnError: defaults to false. When set to true
>> ///   will raise a fatal error, emulating try! instead of try?
>> /// - Parameter errorHandler: processes the error, returns nil
>> ///
>> /// ```swift
>> /// attempt {
>> ///   let mgr = NSFileManager.defaultManager()
>> ///   try mgr.createDirectoryAtPath(
>> ///     "/Users/notarealuser",
>> ///     withIntermediateDirectories: true,
>> ///     attributes: nil)
>> /// }
>> /// ```
>> ///
>> public func attempt<T>(
>>     file fileName: String = __FILE__,
>>     line lineNumber: Int = __LINE__,
>>     crashOnError: Bool = false,
>>     errorHandler: CommonErrorHandlerType = {
>>         // Default handler prints context:error and returns nil
>>         fileName, lineNumber, error in
>>         
>>         /// Retrieve last path component because #fileName is
>>         /// not yet a thing in Swift
>>         let trimmedFileName: String = (fileName as 
>> NSString).lastPathComponent
>>         
>>         /// Force print and return nil like try?
>>         print("Error \(trimmedFileName):\(lineNumber) \(error)")
>>     },
>>     closure: () throws -> T) -> T? {
>>         
>>         do {
>>             // Return executes only if closure succeeds, returning T
>>             return try closure()
>>             
>>         } catch {
>>             // Emulate try! by crashing
>>             if crashOnError {
>>                 print("Fatal error \(fileName):\(lineNumber): \(error)")
>>                 fatalError()
>>             }
>>             
>>             // Execute error handler and return nil
>>             errorHandler(fileName, lineNumber, error)
>>             return nil
>>         }
>> }
>> 
>> 

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to