<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">The error handler doesn't have to be co-linear or even defined in the same call:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">/// consists of filename, line number, error tuple</font></div><div class=""><font face="Menlo" class="">public typealias CommonErrorHandlerType = (String, Int, ErrorType) -> Void</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">/// Default error handler prints context and error</font></div><div class=""><font face="Menlo" class="">public let defaultCommonErrorHandler: CommonErrorHandlerType = {</font></div><div class=""><font face="Menlo" class=""> filePath, lineNumber, error in</font></div><div class=""><font face="Menlo" class=""> let trimmedFileName: String = (filePath as NSString).lastPathComponent</font></div><div class=""><font face="Menlo" class=""> print("Error \(trimmedFileName):\(lineNumber) \(error)")</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><br class=""></div><div class="">If you're doing much more than printing or adding a line-or-two extra then </div><div class="">I don't think you should be using guard, you should be applying do-catch at the call site</div><div class="">or using try (not try? or try!) and forwarding the error handling.</div><div class=""><br class=""></div><div class="">-- E</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 23, 2016, at 8:05 AM, Maximilian Hünenberger <<a href="mailto:m.huenenberger@me.com" class="">m.huenenberger@me.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class=""></div><div class="">Your "attempt" function addresses this issue if someone only wants to print the error:</div><div class=""><br class=""></div><div class="">guard let x = attempt({ try throwingFunction(y) }) else {</div><div class=""> return</div><div class="">}</div><div class="">// prints "<span style="background-color: rgba(255, 255, 255, 0);" class="">Error \(trimmedFileName):\(lineNumber) \(error)"</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">In contrast to</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""><br class=""></span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">guard let x = try? throwingFunction(y) catch {</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""> // you have to make your own print</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class=""> return</span></div><div class=""><span style="background-color: rgba(255, 255, 255, 0);" class="">}</span></div><div class=""><br class=""></div><div class="">---------------------</div><div class=""><br class=""></div><div class="">However if you want to handle the error before you exit the scope it is quite inconvenient:</div><div class=""><br class=""></div><div class="">guard let x = attempt({ _, _, error in /* handle error */ }, { try throwingFunction(y) } ) else {</div><div class=""> return</div><div class="">}</div><div class=""><br class=""></div><div class="">In contrast to:</div><div class=""><br class=""></div><div class="">guard let x = try? throwingFunction(y) catch {</div><div class=""> // handle error</div><div class=""> return</div><div class="">}</div><div class=""><br class=""></div><div class="">- Maximilian</div><div class=""><br class="">Am 14.03.2016 um 18:00 schrieb Erica Sadun <<a href="mailto:erica@ericasadun.com" class="">erica@ericasadun.com</a>>:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 14, 2016, at 10:20 AM, Maximilian Hünenberger via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="auto" class=""><div class=""></div><div class="">How about only allowing "guard try? catch":</div><div class=""><br class=""></div><div class=""> guard let x = try? foo() catch { ... }</div><div class=""><br class=""></div><div class="">This would address both concerns of Chris:</div><div class=""><br class=""></div><div class="">• "<span class="" style="background-color: rgba(255, 255, 255, 0);">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."</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);">• "This shouldn’t be tied to the presence of try, because it already means something (that the enclosed expression can throw). This:</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"> guard let x = try foo() …</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);">Already means “call foo, if it throws, propagate the error. If not, test the returned optional”."</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);">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.</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);">Kind regards</span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);">- Maximilian</span></div></div></div></blockquote></div><div class=""><div class=""><div dir="auto" class=""><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div><div class=""><span class="" style="background-color: rgba(255, 255, 255, 0);"><br class=""></span></div></div></div></div><div class="">I'm not a fan of the notion of guard/catch. However, it occurs to me that my "attempt" code may address this issue.</div><div class="">I've recently updated it to take an arbitrary error handler, which if omitted, simply prints the error. Otherwise it acts like try?</div><div class="">or if you set crashOnError, like try!. It works with guard.</div><div class=""><br class=""></div><div class="">-- E</div><div class=""><br class=""></div><div class=""><div class="">github: <a href="https://github.com/erica/SwiftUtility/blob/master/Sources/CoreError.swift" class="">https://github.com/erica/SwiftUtility/blob/master/Sources/CoreError.swift</a></div></div><div class=""><br class=""></div><div class=""><pre style="word-wrap: break-word; white-space: pre-wrap;" class="">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
}
}
</pre></div><div class=""><br class=""></div><br class=""></div></blockquote></div></div></blockquote></div><br class=""></body></html>