[swift-evolution] Bridging the gap between protocols and protocol extensions

Charles Srstka cocoadev at charlessoft.com
Sat Jan 9 17:39:30 CST 2016


On Jan 9, 2016, at 4:05 PM, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
> 
> From my previous thread, "[Draft Proposal] Require `final` on protocol extension members", I'm getting the sense that many people want straight-up dynamic dispatch from protocol extension methods. That is, protocol extension methods should be treated as if they were included as requirements of the protocol; the implementations provided should be treated as overridable defaults.
> 
> A few questions about that:
> 
> 1. Do people really want this?

I do. There are lots of useful things you could do with dynamically dispatched protocol extension methods that you cannot easily do elegantly. As an example, I could declare this extension on ErrorType:

extension ErrorType {
	var isFileNotFoundError: Bool {
		// Check for all of the possible “File not found” errors in POSIXError, NSCocoaError, NSURLError, NSOSStatusErrorDomain, etc.
		// Then check for NSUnderlyingErrorKey and if it exists, rinse and repeat with that.
	}

	func toNSError() -> NSError {
		return self as NSError
	}
}

A method like this allows one to do things like this:

do {
	try NSFileManager.defaultManager().removeItemAtURL(someURL)
} catch {
	if error.isFileNotFoundError {
		// The file we were trying to delete didn’t exist. Ignore the error
	} else {
		// Okay, something actually went wrong
		NSApp.presentError(error.toNSError())
	}
}

Then, perhaps you define your own error type that has a FileNotFound error condition in it, and would like to override these methods:

enum MyErrorType: ErrorType {
	case FileNotFound(url: NSURL)
	// more cases

	var isFileNotFoundError: Bool {
		// Unfortunately, this will never get called.
		return case .FileNotFound(_) = self
	}

	func toNSError() -> NSError {
		// This won’t get called either. The user will see a lovely “MyErrorType error (Int)” instead of our localized error message.

		switch self {
			case let .FileNotFound(url: url):
				let userInfo = [NSLocalizedFailureReasonErrorKey : String(format: NSLocalizedString(“FNF %@“, comment: “String format: File Not Found error”), url.lastPathComponent)]
				return NSError(domain: “MyErrorType”, code: 1, userInfo: userInfo)
			// other cases
		}
	}
}

For any of the above to work as is, each and every error handler has to do an as? check against every custom error type in your project.

Charles

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160109/6ad17275/attachment.html>


More information about the swift-evolution mailing list