My 2 cents:

Generic errors have caused me problems on multiple occasions.They often make it 
difficult to handle and pass-through arbitrary errors. This pseudo Swift3 code 
is what I have resorted to doing on some projects. 

```
enum MyError : Error
{
        …

        case wrappedError( Error )
}
```

I would go so far as to say that generic errors are an anti-pattern in Swift.

- Chris 


> On Aug 14, 2016, at 6:04 PM, Jon Shier via swift-evolution 
> <[email protected]> wrote:
> 
>       Yes, if you return a single error type it works fine. However, since 
> Alamofire wraps the underlying networking frameworks there’s a need to return 
> the errors returned from them as well, which are now returned as Error. In 
> order to let these errors be returned alongside Alamofire’s errors we’d 
> either have to get rid of the generic error and just use Error or wrap all 
> errors in our error type. So far the least painful method seems to be just 
> getting rid of the generic error and returning Error for everything. That way 
> users will use the same logic they would have had to use anyway and can also 
> provide their own error wrapper if they want. Thankfully (or unfortunately, 
> depending on your point of view), the new pattern is to cast out the various 
> error types, so the previous concern about having to do that is no longer an 
> issue.
> 
> 
> Jon
> 
>> On Aug 14, 2016, at 4:18 AM, Charles Srstka <[email protected] 
>> <mailto:[email protected]>> wrote:
>> 
>>> On Aug 14, 2016, at 2:34 AM, Jon Shier <[email protected] 
>>> <mailto:[email protected]>> wrote:
>>> 
>>>     Sorry Charles, I should’ve been more specific. This isn’t about some 
>>> other type named Error being usable, but about our doubly generic Result 
>>> and other types being usable with Error as the generic error type. If we 
>>> have Result defined as:
>>> 
>>> public enum Result<Value, ErrorType: Error> {
>>>     case success(Value)
>>>     case failure(ErrorType)
>>> }
>>> 
>>> then attempting to create the type Result<Whatever, Error> results in the 
>>> error message I posted. For methods that previously returned 
>>> Result<Whatever, NSError>, where the NSError is either a system error or an 
>>> Alamofire one, this is something of a problem. Of course, removing the 
>>> generic error type fixes this but may have an undesirable usability impact, 
>>> as making Result double generic was the primary reason behind the quick 
>>> upgrade between Alamofire 2 and 3. I think it’s less of a problem now, as 
>>> having to enumerate all of the different expected error types is how user’s 
>>> are supposed to interact with Error in the first place, but at the time it 
>>> wasn’t desirable to try and force everything through ErrorProtocol for that 
>>> reason. Perhaps this is a good compromise, where instead of returning all 
>>> NSErrors from the framework and allowing consumers to add their own to the 
>>> mix we’ll just create our own AFError type (whether enum or struct) and 
>>> then anything coming back will have to be checked for that type in addition 
>>> to the system types. From my testing it looks like users could still wrap 
>>> everything coming in by capturing the underlying Error.
>> 
>> Still seems to be working well, unless I’m misunderstanding what you’re 
>> trying to do:
>> 
>> import Foundation
>> 
>> enum Result<Value, ErrorType: Error> {
>>     case success(Value)
>>     case failure(ErrorType)
>> }
>> 
>> struct MyThing {
>>     enum Error: Swift.Error, LocalizedError {
>>         case doesNotCompute
>>         case imSorryDave
>>         case mustSterilize
>>         case irrelevant
>>         case endOfLine
>>         
>>         var failureReason: String? {
>>             switch self {
>>             case .doesNotCompute:
>>                 return "Does Not Compute! Does Not Compute! Does Not 
>> Compute!"
>>             case .imSorryDave:
>>                 return "I'm sorry Dave, I'm afraid I can't do that."
>>             case .mustSterilize:
>>                 return "Error! Must Sterilize! Must 
>> Steeerrrrilllliiiiiiizzzzzzeeeeeee"
>>             case .irrelevant:
>>                 return "Irrelevant. Resistance is futile."
>>             case .endOfLine:
>>                 return "End of Line!"
>>             }
>>         }
>>     }
>>     
>>     func trySomething(shouldWork: Bool, completionHandler: (Result<String, 
>> Error>) -> ()) {
>>         if shouldWork {
>>             completionHandler(.success("It worked!"))
>>         } else {
>>             completionHandler(.failure(Error.imSorryDave))
>>         }
>>     }
>> }
>> 
>> let thing = MyThing()
>> 
>> let completionHandler = { (result: Result<String, MyThing.Error>) in
>>     switch result {
>>     case let .success(value):
>>         print("returned '\(value)'")
>>     case let .failure(error):
>>         print("error: \(error.localizedDescription)")
>>     }
>> }
>> 
>> thing.trySomething(shouldWork: true, completionHandler: completionHandler)
>> thing.trySomething(shouldWork: false, completionHandler: completionHandler)
>> 
>> returned 'It worked!'
>> error: The operation couldn’t be completed. I'm sorry Dave, I'm afraid I 
>> can't do that.
>> Program ended with exit code: 0
>> 
>> Charles
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

Reply via email to