Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can any Error be unconditionally converted to NSError?

Tags:

swift

nserror

A lot of times, I'll receive a Swift Error object from a framework, which is really an NSError.

In order to access its information (e.g. code), I need to cast it to an NSError:

(error as NSError).code == ....

Why is this just an unconditional as? If I design my own error class that conforms to Error, it won't necessarily be an NSError, so how can this be the correct way to perform this cast?

Is there some kind of special case in the type system? This is a downcast that behaves like an upcast.

like image 598
Bill Avatar asked Jul 30 '18 22:07

Bill


People also ask

Does NSError conform to error?

It consists of a predefined error domain, a domain-specific error code, and a user info dictionary containing application-specific information. Error is a Swift protocol which classes, structs and enums can and NSError does conform to. A type representing an error value that can be thrown.

What is made up of NSError object?

The core attributes of an NSError object are an error domain (represented by a string), a domain-specific error code and a user info dictionary containing application specific information.

What is NSError in Swift?

Information about an error condition including a domain, a domain-specific error code, and application-specific information.

How to fix NS_Error_Failure error?

It is very possible that the cause of the NS_ERROR_FAILURE error is because you have saved a state of an OS. Therefore, to fix it, you must remove the VM.

What does TypeError only integer scalar arrays can be converted to scalar?

TypeError: only integer scalar arrays can be converted to a scalar index 1. You attempted to perform array indexing on a list. 2. You attempted to concatenate two matrices using incorrect syntax. The following examples shows how to avoid these errors in both scenarios. Example 1: You attempted to perform array indexing on a list.

How to fix error converting data type varchar to numeric?

How to fix error converting data type varchar to numeric. The step-by-step way to quickly convert these characters is to extract all the characters on the left side of the decimal place, seen in the below T-SQL code using the LEFT function: Next, we want to extract the characters after the decimal place, using both the SUBSTRING function ...

How to fix NS_error_failure while trying to launch a VM in VirtualBox?

If you are facing the NS_ERROR_FAILURE while trying to launch a VM in VirtualBox, then firstly, you must discard the saved state. Go to the VM that is having the issue, select it can click on the Discard button from the top menu of the Virtual machine Window.


1 Answers

I believe the capability for Error to be convertible to NSError is hardcoded into the compiler, and the actual bridging is implemented in the Swift runtime.

In runtime/ErrorObject.mm, I found this comment:

// This implements the object representation of the standard Error
// type, which represents recoverable errors in the language. This
// implementation is designed to interoperate efficiently with Cocoa libraries
// by:
// - ...
// - allowing a native Swift error to lazily "become" an NSError when
//   passed into Cocoa, allowing for cheap Swift to Cocoa interop

And this function:

/// Take an Error box and turn it into a valid NSError instance.
id
swift::_swift_stdlib_bridgeErrorToNSError(SwiftError *errorObject) {
    ...

  // Otherwise, calculate the domain, code, and user info, and
  // initialize the NSError.
  auto value = SwiftError::getIndirectValue(&errorObject);
  auto type = errorObject->getType();
  auto witness = errorObject->getErrorConformance();

  NSString *domain = getErrorDomainNSString(value, type, witness);
  NSInteger code = getErrorCode(value, type, witness);
  NSDictionary *userInfo = getErrorUserInfoNSDictionary(value, type, witness);

  ...
}

The ErrorHandling.rst document says this about the rationale:

It should be possible to turn an arbitrary Swift enum that conforms to Error into an NSError by using the qualified type name as the domain key, the enumerator as the error code, and turning the payload into user data.

(Parts of the document may be outdated.)

And this is (I think) at least one part in the type checker were the information that Error is convertible to NSError is encoded (there are probably more):

  // Check whether the type is an existential that contains
  // Error. If so, it's bridged to NSError.
  if (type->isExistentialWithError()) {
    if (auto nsErrorDecl = getNSErrorDecl()) {
      // The corresponding value type is Error.
      if (bridgedValueType)
        *bridgedValueType = getErrorDecl()->getDeclaredInterfaceType();

      return nsErrorDecl->getDeclaredInterfaceType();
    }
  }
like image 162
Ole Begemann Avatar answered Oct 27 '22 08:10

Ole Begemann