Amendment to SE-0112: Default values for errorDomain and errorCode


(Charles Srstka) #1

MOTIVATION:

SE-0112 includes the CustomNSError protocol, which includes the properties errorDomain, errorCode, and errorUserInfo. These properties can be used to tell Swift how to convert an error to an NSError. However, there are no default implementations for errorDomain and errorCode, and there is no way to access the default values for _domain and _code that Error enums get in Swift. Thus, even if all one wanted to do was to provide a value for NSURLErrorKey, one has to do all this:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  static var errorDomain: String {
    return “com.MyCompany.MyApp.MyError”
  }

  var errorCode: Int {
    switch self {
    case .foo(_):
      return 1
    case .bar(_):
      return 2
    case .baz(_):
      return 3
    }
  }

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

Notice how far down you have to read before you finally get to the part that constructs the interesting information.

PROPROSED SOLUTION:

Add default implementations for all the properties in CustomNSError.

DETAILED DESIGN:

The implementations for errorCode and errorDomain will simply provide the default values of _code and _domain already provided by Swift enums. The default implementation for errorUserInfo will simply return an empty dictionary.

This would allow the above enum to be written simply as:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

and the frameworks would provide something appropriate for the domain and code.

Charles


(Douglas Gregor) #2

+1, this seems entirely reasonable to me, and probably should have been part of the original SE-0112.

  - Doug

···

On Aug 5, 2016, at 4:32 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

MOTIVATION:

SE-0112 includes the CustomNSError protocol, which includes the properties errorDomain, errorCode, and errorUserInfo. These properties can be used to tell Swift how to convert an error to an NSError. However, there are no default implementations for errorDomain and errorCode, and there is no way to access the default values for _domain and _code that Error enums get in Swift. Thus, even if all one wanted to do was to provide a value for NSURLErrorKey, one has to do all this:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  static var errorDomain: String {
    return “com.MyCompany.MyApp.MyError”
  }

  var errorCode: Int {
    switch self {
    case .foo(_):
      return 1
    case .bar(_):
      return 2
    case .baz(_):
      return 3
    }
  }

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

Notice how far down you have to read before you finally get to the part that constructs the interesting information.

PROPROSED SOLUTION:

Add default implementations for all the properties in CustomNSError.

DETAILED DESIGN:

The implementations for errorCode and errorDomain will simply provide the default values of _code and _domain already provided by Swift enums. The default implementation for errorUserInfo will simply return an empty dictionary.

This would allow the above enum to be written simply as:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

and the frameworks would provide something appropriate for the domain and code.


(David Sweeris) #3

+1

···

Sent from my iPhone

On Aug 5, 2016, at 18:32, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

MOTIVATION:

SE-0112 includes the CustomNSError protocol, which includes the properties errorDomain, errorCode, and errorUserInfo. These properties can be used to tell Swift how to convert an error to an NSError. However, there are no default implementations for errorDomain and errorCode, and there is no way to access the default values for _domain and _code that Error enums get in Swift. Thus, even if all one wanted to do was to provide a value for NSURLErrorKey, one has to do all this:

enum MyError: CustomNSError {
   case foo(URL)
   case bar(URL)
   case baz(URL)

   static var errorDomain: String {
       return “com.MyCompany.MyApp.MyError”
   }

   var errorCode: Int {
       switch self {
       case .foo(_):
           return 1
       case .bar(_):
           return 2
       case .baz(_):
           return 3
       }
   }

   var errorUserInfo: [String : NSObject] {
       // construct the actual user info
   }
}

Notice how far down you have to read before you finally get to the part that constructs the interesting information.

PROPROSED SOLUTION:

Add default implementations for all the properties in CustomNSError.

DETAILED DESIGN:

The implementations for errorCode and errorDomain will simply provide the default values of _code and _domain already provided by Swift enums. The default implementation for errorUserInfo will simply return an empty dictionary.

This would allow the above enum to be written simply as:

enum MyError: CustomNSError {
   case foo(URL)
   case bar(URL)
   case baz(URL)

   var errorUserInfo: [String : NSObject] {
       // construct the actual user info
   }
}

and the frameworks would provide something appropriate for the domain and code.

Charles

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Douglas Gregor) #4

The core team discussed this and will take this as an amendment to SE-0112. Charles, can you turn this into a pull request to update the SE-0112 document?

  - Doug

···

On Aug 5, 2016, at 4:32 PM, Charles Srstka via swift-evolution <swift-evolution@swift.org> wrote:

MOTIVATION:

SE-0112 includes the CustomNSError protocol, which includes the properties errorDomain, errorCode, and errorUserInfo. These properties can be used to tell Swift how to convert an error to an NSError. However, there are no default implementations for errorDomain and errorCode, and there is no way to access the default values for _domain and _code that Error enums get in Swift. Thus, even if all one wanted to do was to provide a value for NSURLErrorKey, one has to do all this:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  static var errorDomain: String {
    return “com.MyCompany.MyApp.MyError”
  }

  var errorCode: Int {
    switch self {
    case .foo(_):
      return 1
    case .bar(_):
      return 2
    case .baz(_):
      return 3
    }
  }

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

Notice how far down you have to read before you finally get to the part that constructs the interesting information.

PROPROSED SOLUTION:

Add default implementations for all the properties in CustomNSError.

DETAILED DESIGN:

The implementations for errorCode and errorDomain will simply provide the default values of _code and _domain already provided by Swift enums. The default implementation for errorUserInfo will simply return an empty dictionary.

This would allow the above enum to be written simply as:

enum MyError: CustomNSError {
  case foo(URL)
  case bar(URL)
  case baz(URL)

  var errorUserInfo: [String : NSObject] {
    // construct the actual user info
  }
}

and the frameworks would provide something appropriate for the domain and code.


(Tino) #5

Why not simply add those default implementations to Error?
I can't see the value of hiding read-only properties that are already there...


(Douglas Gregor) #6

Domain, code, and user-info are useful for Cocoa interoperability but aren’t otherwise necessary in Swift, which captures that information more directly in the (concrete) error types that conform to Error.

  - Doug

···

On Sep 2, 2016, at 5:59 AM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

Why not simply add those default implementations to Error?
I can't see the value of hiding read-only properties that are already there…


(Tino) #7

Domain, code, and user-info are useful for Cocoa interoperability but aren’t otherwise necessary in Swift, which captures that information more directly in the (concrete) error types that conform to Error.

So the only motivation to hide _code and _domain is to discourage Objective-C-like dispatching in Swift, right?
For me, that would not be enough motivation to require something like "CustomNSError", but probably this isn't the opinion of the majority.

I still think Error should be a legacy-type that is only needed for interoperability… but removing the restriction that only Error-types can be thrown is additive, so I won't continue discussing this now.

- Tino


(Douglas Gregor) #8

Domain, code, and user-info are useful for Cocoa interoperability but aren’t otherwise necessary in Swift, which captures that information more directly in the (concrete) error types that conform to Error.

So the only motivation to hide _code and _domain is to discourage Objective-C-like dispatching in Swift, right?

The only reason _code and _domain exist is for Objective-C interoperability. They are not part of the Swift error model.

For me, that would not be enough motivation to require something like "CustomNSError", but probably this isn't the opinion of the majority.

CustomNSError exists for cases where one wants to customize how a Swift error is translated into NSError. It’s for fine-grained control of something that generally shouldn’t matter to Swift developers.

I still think Error should be a legacy-type that is only needed for interoperability… but removing the restriction that only Error-types can be thrown is additive, so I won't continue discussing this now.

FWIW, I am completely against the direction you propose, for a number of reasons:

* If we take away the Error abstraction, then the way to deal with errors in general is via Any, which erases important meaning from the static type system
* Throwing any old type (let’s throw an Int! A closure!) makes it *very* hard to improve handling of that error type, e.g., you’re not going to be able to retroactively make Int or String conform to LocalizedError to provide a better user experience.
* There are useful extensions of the Error protocol in Foundation, e.g., the “localizedDescription” property, that one wouldn’t (and couldn’t) put onto ‘Any’. There might be more of such extensions in the future

  - Doug

···

On Sep 8, 2016, at 3:46 AM, Tino Heth <2th@gmx.de> wrote: