为什么在Swift中‘扔’字不安全?

时间:2022-01-11 16:04:31

The biggest misunderstanding for me in Swift is the throws keyword. Consider the following piece of code:

对我来说,在Swift中最大的误解是throw关键词。考虑下面的代码:

func myUsefulFunction() throws

We cannot really understand what kind of error it will throw. The only thing we know is that it might throw some error. The only way to understand what the error might be is by looking at the documentation or checking the error at runtime.

我们无法真正理解它会抛出什么样的错误。我们唯一知道的是它可能会抛出一些错误。理解错误的唯一方法是查看文档或在运行时检查错误。

But isn't this against Swift's nature? Swift has powerful generics and a type system to make the code expressive, yet it feels as if throws is exactly opposite because you cannot get anything about the error from looking at the function signature.

但这难道不违背斯威夫特的天性吗?Swift具有强大的泛型和类型系统,可以使代码具有表现力,但它的感觉就好像是抛出正好相反,因为您无法从查看函数签名中得到任何关于错误的信息。

Why is that so? Or have I missed something important and mistook the concept?

为什么是这样呢?还是我错过了一些重要的东西,把这个概念搞错了?

2 个解决方案

#1


21  

The choice is a deliberate design decision.

选择是经过深思熟虑的设计决定。

They did not want the situation where you don't need to declare exception throwing as in Objective-C, C++ and C# because that makes callers have to either assume all functions throw exceptions and include boilerplate to handle exceptions that might not happen, or to just ignore the possibility of exceptions. Neither of these are ideal and the second makes exceptions unusable except for the case when you want to terminate the program because you can't guarantee that every function in the call stack has correctly deallocated resources when the stack is unwound.

他们不希望出现这样的情况:您不需要像Objective-C、c++和c#中那样声明异常抛出,因为这使得调用者必须假设所有函数抛出异常并包含样板来处理可能不会发生的异常,或者忽略异常发生的可能性。这两种方法都不是理想的,第二种方法使异常不可用,除非您想终止程序,因为您不能保证调用堆栈中的每个函数在堆栈解除缠绕时都正确地分配了资源。

The other extreme is the idea you have advocated and that each type of exception thrown can be declared. Unfortunately, people seem to object to the consequence of this which is that you have large numbers of catch blocks so you can handle each type of exception. So, for instance, in Java, they will throw Exception reducing the situation to the same as we have in Swift or worse, they use unchecked exceptions so you can ignore the problem altogether. The GSON library is an example of the latter approach.

另一个极端是您所提倡的思想,并且可以声明抛出的每种异常类型。不幸的是,人们似乎反对这种结果,即您拥有大量的捕获块,因此您可以处理每种类型的异常。因此,例如,在Java中,他们会抛出异常,将情况降低到与我们在Swift或更糟的情况下相同的程度,他们使用未检查的异常,因此您可以完全忽略这个问题。GSON库就是后一种方法的一个例子。

We chose to use unchecked exceptions to indicate a parsing failure. This is primarily done because usually the client can not recover from bad input, and hence forcing them to catch a checked exception results in sloppy code in the catch() block.

我们选择使用未检查的异常来指示解析失败。这主要是因为客户端通常无法从糟糕的输入中恢复,因此强制他们捕获一个检查过的异常会导致catch()块中代码的松散。

https://github.com/google/gson/blob/master/GsonDesignDocument.md

https://github.com/google/gson/blob/master/GsonDesignDocument.md

That is an egregiously bad decision. "Hi, you can't be trusted to do your own error handling, so your application should crash instead".

这是一个极其糟糕的决定。“您好,您不能信任您自己进行错误处理,因此您的应用程序应该崩溃。”

Personally, I think Swift gets the balance about right. You have to handle errors, but you don't have to write reams of catch statements to do it. If they went any further, people would find ways to subvert the mechanism.

就我个人而言,我认为斯威夫特在正确的方面取得了平衡。您必须处理错误,但不需要编写大量的catch语句。如果他们走得更远,人们就会想方设法破坏这种机制。

The full rationale for the design decision is at https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

设计决策的全部依据是https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

EDIT

编辑

There seems to be some people having problems with some of the things I have said. So here is an explanation.

似乎有些人对我说的有些话有意见。这是一个解释。

There are two broad categories of reasons why a program might throw an exception.

程序可能抛出异常的原因有两大类。

  • unexpected conditions in the environment external to the program such as an IO error on a file or malformed data. These are errors that the application can usually handle, for example by reporting the error to the user and allowing them to choose a different course of action.
  • 程序外部环境中的意外情况,如文件上的IO错误或格式错误的数据。这些是应用程序通常可以处理的错误,例如向用户报告错误并允许用户选择不同的操作过程。
  • Errors in programming such as null pointer or array bound errors. The proper way to fix these is for the programmer to make a code change.
  • 编程中的错误,如空指针或数组绑定错误。解决这些问题的正确方法是让程序员进行代码更改。

The second type of error should not, in general be caught, because they indicate a false assumption about the environment that could mean the program's data is corrupt. There my be no way to continue safely, so you have to abort.

第二种错误通常不应该被捕获,因为它们表明了对环境的错误假设,这可能意味着程序的数据被破坏了。我没有办法继续安全,所以你必须放弃。

The first type of error usually can be recovered, but in order to recover safely, every stack frame has to be unwound correctly which means that the function corresponding to each stack frame must be aware that the functions it calls may throw an exception and take steps to ensure that everything gets cleaned up consistently if an exception is thrown, with, for example, a finally block or equivalent. If the compiler doesn't provide support for telling the programmer they have forgotten to plan for exceptions, the programmer won't always plan for exceptions and will write code that leaks resources or leaves data in an inconsistent state.

第一类型的错误通常可以恢复,但为了恢复安全,每一个堆栈帧必须正确解除这意味着函数对应于每个堆栈帧必须意识到它调用的函数可能抛出异常并采取措施确保所有如果抛出一个异常,会被清除,例如,finally块或同等学历。如果编译器不支持告诉程序员他们已经忘记了对异常的计划,程序员将不会总是计划异常,并且会编写代码来泄漏资源或使数据处于不一致的状态。

The reason why the gson attitude is so appalling is because they are saying you can't recover from a parse error (actually, worse, they are telling you that you lack the skills to recover from a parse error). That is a ridiculous thing to assert, people attempt to parse invalid JSON files all the time. Is it a good thing that my program crashes if somebody selects an XML file by mistake? No isn't. It should report the problem and ask them to select a different file.

gson态度如此糟糕的原因是,他们说您无法从解析错误中恢复(实际上,更糟糕的是,他们告诉您您缺乏从解析错误中恢复的技能)。这是一个荒谬的断言,人们总是试图解析无效的JSON文件。如果有人错误地选择了XML文件,我的程序会崩溃,这是好事吗?没有没有。它应该报告问题并要求他们选择不同的文件。

And the gson thing was, by the way, just an example of why using unchecked exceptions for errors you can recover from is bad. If I do want to recover from somebody selecting an XML file, I need to catch Java runtime exceptions, but which ones? Well I could look in the Gson docs to find out, assuming they are correct and up to date. If they had gone with checked exceptions, the API would tell me which exceptions to expect and the compiler would tell me if I don't handle them.

顺便说一下,gson事件只是一个例子,说明为什么对可以恢复的错误使用未检查的异常是不好的。如果我确实想从选择XML文件的人那里恢复,我需要捕获Java运行时异常,但是哪些异常呢?我可以在Gson文档中查找,假设它们是正确的并且是最新的。如果它们带有已检查的异常,API将告诉我预期的异常,如果我不处理它们,编译器将告诉我。

#2


29  

I was an early proponent of typed errors in Swift. This is how the Swift team convinced me I was wrong.

我是斯威夫特打字错误的早期支持者。这就是斯威夫特团队让我相信我错了的原因。

Strongly typed errors are fragile in ways that can lead to poor API evolution. If the API promises to throw only one of precisely 3 errors, then when a fourth error condition arises in a later release, I have a choice: I bury it somehow in the existing 3, or I force every caller to rewrite their error handling code to deal with it. Since it wasn't in the original 3, it probably isn't a very common condition, and this puts strong pressure on APIs not to expand their list of errors, particularly once a framework has extensive use over a long time (think: Foundation).

强类型错误是脆弱的,会导致糟糕的API演化。如果API承诺只抛出3个错误中的一个,那么当在以后的版本中出现第四个错误条件时,我有一个选择:以某种方式将它隐藏在现有的3中,或者强迫每个调用者重写他们的错误处理代码来处理它。由于它不在最初的3中,所以它可能不是一个非常常见的条件,这给api带来了很大的压力,使它们不能扩展错误列表,特别是在一个框架在很长一段时间内广泛使用之后(请考虑:Foundation)。

Of course with open enums, we can avoid that, but an open enum achieves none of the goals of a strongly typed error. It is basically an untyped error again because you still need a "default."

当然,对于open enum,我们可以避免这种情况,但是open enum不会实现强类型错误的任何目标。它基本上是一个无类型错误,因为您仍然需要一个“默认值”。

You might still say "at least I know where the error comes from with an open enum," but this tends to make things worse. Say I have a logging system and it tries to write and gets an IO error. What should it return? Swift doesn't have algebraic data types (I can't say () -> IOError | LoggingError), so I'd probably have to wrap IOError into LoggingError.IO(IOError) (which forces every layer to explicitly rewrap; you can't have rethrows very often). Even if it did have ADTs, do you really want IOError | MemoryError | LoggingError | UnexpectedError | ...? Once you have a few layers, I wind up with layer upon layer of wrapping of some underlying "root cause" that have to be painfully unwrapped to deal with.

您可能仍然会说“至少我知道open enum的错误来自哪里”,但这往往会使事情变得更糟。假设我有一个日志系统,它试图写入并得到一个IO错误。应该返回什么?Swift没有代数数据类型(我不能说()-> io| LoggingError),所以我可能必须将IOError包装成LoggingError. io (IOError)(它强制每个层显式地重新包装;你不可能经常得到回覆)。即使它有adt,你真的想要IOError | MemoryError | LoggingError |意想不到|吗?一旦你有了几层,我就会层层包裹一些潜在的“根本原因”,而这些“根本原因”必须经过痛苦的处理才能处理。

And how are you going to deal with it? In the overwhelming majority of cases, what do catch blocks look like?

你要怎么处理呢?在绝大多数情况下,捕捉块是什么样子的?

} catch {
    logError(error)
    return
}

It is extremely uncommon for Cocoa programs (i.e. "apps") to dig deeply into the exact root cause of the error and perform different operations based on each precise case. There might be one or two cases that have a recovery, and the rest are things you couldn't do anything about anyway. (This is a common issue in Java with checked exception that aren't just Exception; it's not like no one has gone down this path before. I like Yegor Bugayenko's arguments for checked exceptions in Java which basically argues as his preferred Java practice exactly the Swift solution.)

这对于Cocoa程序来说是非常不常见的。“应用”)深入挖掘错误的真正根源,并根据每个精确的案例执行不同的操作。可能有一两种情况会出现复苏,剩下的事情你无论如何都无能为力。(这在Java中是一个常见的问题,但它不只是例外;这并不是说以前没有人走过这条路。我喜欢Yegor Bugayenko关于Java中已检查异常的论点,基本上认为他偏爱的Java实践正是Swift解决方案。

This is not to say that there aren't cases where strongly typed errors would be extremely useful. But there are two answers to this: first, you're free to implement strongly typed errors on your own with an enum and get pretty good compiler enforcement. Not perfect (you still need a default catch outside the switch statement, but not inside), but pretty good if you follow some conventions on your own.

这并不是说没有强类型错误非常有用的情况。但是有两个答案:首先,您可以使用enum自己实现强类型错误,并获得相当好的编译器执行。不完美(在switch语句之外仍然需要一个默认的catch,但不是在内部),但是如果您自己遵循一些约定,就非常好了。

Second, if this use case turns out to be important (and it might), it is not difficult to add strongly typed errors later for those cases without breaking the common cases that want fairly generic error handling. They would just add syntax:

其次,如果这个用例是重要的(并且它可能是重要的),那么在这些情况下添加强类型错误并不困难,而不会破坏那些需要相当通用的错误处理的常见情况。他们只需要添加语法:

func something() throws MyError { }

And callers would have to treat that as a strong type.

打电话的人会把这当成一种强烈的类型。

Last of all, for strongly typed errors to be of much use, Foundation would need to throw them since it is the largest producer of errors in the system. (How often do you really create an NSError from scratch compared to deal with one generated by Foundation?) That would be a massive overhaul of Foundation and very hard to keep compatible with existing code and ObjC. So typed errors would need to be absolutely fantastic at solving very common Cocoa problems to be worth considering as the default behavior. It couldn't be just a little nicer (let alone have the problems described above).

最后,对于强类型错误的使用,Foundation将需要抛出它们,因为它是系统中最大的错误产生者。(与处理Foundation生成的NSError相比,您真正从头创建NSError的频率是多少?)这将是对基础的大规模改革,并且很难与现有的代码和ObjC兼容。因此,类型化错误必须在解决非常常见的Cocoa问题上非常出色,才能作为默认行为考虑。这是再好不过的了(更不用说上面描述的问题了)。

So none of this is to say that untyped errors are the 100% perfect solution to error handling in all cases. But these arguments convinced me that it was the right way to go in Swift today.

所以这并不是说非类型化错误是所有情况下错误处理的100%完美解决方案。但这些论点让我相信,这是如今迅速发展的正确方式。

#1


21  

The choice is a deliberate design decision.

选择是经过深思熟虑的设计决定。

They did not want the situation where you don't need to declare exception throwing as in Objective-C, C++ and C# because that makes callers have to either assume all functions throw exceptions and include boilerplate to handle exceptions that might not happen, or to just ignore the possibility of exceptions. Neither of these are ideal and the second makes exceptions unusable except for the case when you want to terminate the program because you can't guarantee that every function in the call stack has correctly deallocated resources when the stack is unwound.

他们不希望出现这样的情况:您不需要像Objective-C、c++和c#中那样声明异常抛出,因为这使得调用者必须假设所有函数抛出异常并包含样板来处理可能不会发生的异常,或者忽略异常发生的可能性。这两种方法都不是理想的,第二种方法使异常不可用,除非您想终止程序,因为您不能保证调用堆栈中的每个函数在堆栈解除缠绕时都正确地分配了资源。

The other extreme is the idea you have advocated and that each type of exception thrown can be declared. Unfortunately, people seem to object to the consequence of this which is that you have large numbers of catch blocks so you can handle each type of exception. So, for instance, in Java, they will throw Exception reducing the situation to the same as we have in Swift or worse, they use unchecked exceptions so you can ignore the problem altogether. The GSON library is an example of the latter approach.

另一个极端是您所提倡的思想,并且可以声明抛出的每种异常类型。不幸的是,人们似乎反对这种结果,即您拥有大量的捕获块,因此您可以处理每种类型的异常。因此,例如,在Java中,他们会抛出异常,将情况降低到与我们在Swift或更糟的情况下相同的程度,他们使用未检查的异常,因此您可以完全忽略这个问题。GSON库就是后一种方法的一个例子。

We chose to use unchecked exceptions to indicate a parsing failure. This is primarily done because usually the client can not recover from bad input, and hence forcing them to catch a checked exception results in sloppy code in the catch() block.

我们选择使用未检查的异常来指示解析失败。这主要是因为客户端通常无法从糟糕的输入中恢复,因此强制他们捕获一个检查过的异常会导致catch()块中代码的松散。

https://github.com/google/gson/blob/master/GsonDesignDocument.md

https://github.com/google/gson/blob/master/GsonDesignDocument.md

That is an egregiously bad decision. "Hi, you can't be trusted to do your own error handling, so your application should crash instead".

这是一个极其糟糕的决定。“您好,您不能信任您自己进行错误处理,因此您的应用程序应该崩溃。”

Personally, I think Swift gets the balance about right. You have to handle errors, but you don't have to write reams of catch statements to do it. If they went any further, people would find ways to subvert the mechanism.

就我个人而言,我认为斯威夫特在正确的方面取得了平衡。您必须处理错误,但不需要编写大量的catch语句。如果他们走得更远,人们就会想方设法破坏这种机制。

The full rationale for the design decision is at https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

设计决策的全部依据是https://github.com/apple/swift/blob/master/docs/ErrorHandlingRationale.rst

EDIT

编辑

There seems to be some people having problems with some of the things I have said. So here is an explanation.

似乎有些人对我说的有些话有意见。这是一个解释。

There are two broad categories of reasons why a program might throw an exception.

程序可能抛出异常的原因有两大类。

  • unexpected conditions in the environment external to the program such as an IO error on a file or malformed data. These are errors that the application can usually handle, for example by reporting the error to the user and allowing them to choose a different course of action.
  • 程序外部环境中的意外情况,如文件上的IO错误或格式错误的数据。这些是应用程序通常可以处理的错误,例如向用户报告错误并允许用户选择不同的操作过程。
  • Errors in programming such as null pointer or array bound errors. The proper way to fix these is for the programmer to make a code change.
  • 编程中的错误,如空指针或数组绑定错误。解决这些问题的正确方法是让程序员进行代码更改。

The second type of error should not, in general be caught, because they indicate a false assumption about the environment that could mean the program's data is corrupt. There my be no way to continue safely, so you have to abort.

第二种错误通常不应该被捕获,因为它们表明了对环境的错误假设,这可能意味着程序的数据被破坏了。我没有办法继续安全,所以你必须放弃。

The first type of error usually can be recovered, but in order to recover safely, every stack frame has to be unwound correctly which means that the function corresponding to each stack frame must be aware that the functions it calls may throw an exception and take steps to ensure that everything gets cleaned up consistently if an exception is thrown, with, for example, a finally block or equivalent. If the compiler doesn't provide support for telling the programmer they have forgotten to plan for exceptions, the programmer won't always plan for exceptions and will write code that leaks resources or leaves data in an inconsistent state.

第一类型的错误通常可以恢复,但为了恢复安全,每一个堆栈帧必须正确解除这意味着函数对应于每个堆栈帧必须意识到它调用的函数可能抛出异常并采取措施确保所有如果抛出一个异常,会被清除,例如,finally块或同等学历。如果编译器不支持告诉程序员他们已经忘记了对异常的计划,程序员将不会总是计划异常,并且会编写代码来泄漏资源或使数据处于不一致的状态。

The reason why the gson attitude is so appalling is because they are saying you can't recover from a parse error (actually, worse, they are telling you that you lack the skills to recover from a parse error). That is a ridiculous thing to assert, people attempt to parse invalid JSON files all the time. Is it a good thing that my program crashes if somebody selects an XML file by mistake? No isn't. It should report the problem and ask them to select a different file.

gson态度如此糟糕的原因是,他们说您无法从解析错误中恢复(实际上,更糟糕的是,他们告诉您您缺乏从解析错误中恢复的技能)。这是一个荒谬的断言,人们总是试图解析无效的JSON文件。如果有人错误地选择了XML文件,我的程序会崩溃,这是好事吗?没有没有。它应该报告问题并要求他们选择不同的文件。

And the gson thing was, by the way, just an example of why using unchecked exceptions for errors you can recover from is bad. If I do want to recover from somebody selecting an XML file, I need to catch Java runtime exceptions, but which ones? Well I could look in the Gson docs to find out, assuming they are correct and up to date. If they had gone with checked exceptions, the API would tell me which exceptions to expect and the compiler would tell me if I don't handle them.

顺便说一下,gson事件只是一个例子,说明为什么对可以恢复的错误使用未检查的异常是不好的。如果我确实想从选择XML文件的人那里恢复,我需要捕获Java运行时异常,但是哪些异常呢?我可以在Gson文档中查找,假设它们是正确的并且是最新的。如果它们带有已检查的异常,API将告诉我预期的异常,如果我不处理它们,编译器将告诉我。

#2


29  

I was an early proponent of typed errors in Swift. This is how the Swift team convinced me I was wrong.

我是斯威夫特打字错误的早期支持者。这就是斯威夫特团队让我相信我错了的原因。

Strongly typed errors are fragile in ways that can lead to poor API evolution. If the API promises to throw only one of precisely 3 errors, then when a fourth error condition arises in a later release, I have a choice: I bury it somehow in the existing 3, or I force every caller to rewrite their error handling code to deal with it. Since it wasn't in the original 3, it probably isn't a very common condition, and this puts strong pressure on APIs not to expand their list of errors, particularly once a framework has extensive use over a long time (think: Foundation).

强类型错误是脆弱的,会导致糟糕的API演化。如果API承诺只抛出3个错误中的一个,那么当在以后的版本中出现第四个错误条件时,我有一个选择:以某种方式将它隐藏在现有的3中,或者强迫每个调用者重写他们的错误处理代码来处理它。由于它不在最初的3中,所以它可能不是一个非常常见的条件,这给api带来了很大的压力,使它们不能扩展错误列表,特别是在一个框架在很长一段时间内广泛使用之后(请考虑:Foundation)。

Of course with open enums, we can avoid that, but an open enum achieves none of the goals of a strongly typed error. It is basically an untyped error again because you still need a "default."

当然,对于open enum,我们可以避免这种情况,但是open enum不会实现强类型错误的任何目标。它基本上是一个无类型错误,因为您仍然需要一个“默认值”。

You might still say "at least I know where the error comes from with an open enum," but this tends to make things worse. Say I have a logging system and it tries to write and gets an IO error. What should it return? Swift doesn't have algebraic data types (I can't say () -> IOError | LoggingError), so I'd probably have to wrap IOError into LoggingError.IO(IOError) (which forces every layer to explicitly rewrap; you can't have rethrows very often). Even if it did have ADTs, do you really want IOError | MemoryError | LoggingError | UnexpectedError | ...? Once you have a few layers, I wind up with layer upon layer of wrapping of some underlying "root cause" that have to be painfully unwrapped to deal with.

您可能仍然会说“至少我知道open enum的错误来自哪里”,但这往往会使事情变得更糟。假设我有一个日志系统,它试图写入并得到一个IO错误。应该返回什么?Swift没有代数数据类型(我不能说()-> io| LoggingError),所以我可能必须将IOError包装成LoggingError. io (IOError)(它强制每个层显式地重新包装;你不可能经常得到回覆)。即使它有adt,你真的想要IOError | MemoryError | LoggingError |意想不到|吗?一旦你有了几层,我就会层层包裹一些潜在的“根本原因”,而这些“根本原因”必须经过痛苦的处理才能处理。

And how are you going to deal with it? In the overwhelming majority of cases, what do catch blocks look like?

你要怎么处理呢?在绝大多数情况下,捕捉块是什么样子的?

} catch {
    logError(error)
    return
}

It is extremely uncommon for Cocoa programs (i.e. "apps") to dig deeply into the exact root cause of the error and perform different operations based on each precise case. There might be one or two cases that have a recovery, and the rest are things you couldn't do anything about anyway. (This is a common issue in Java with checked exception that aren't just Exception; it's not like no one has gone down this path before. I like Yegor Bugayenko's arguments for checked exceptions in Java which basically argues as his preferred Java practice exactly the Swift solution.)

这对于Cocoa程序来说是非常不常见的。“应用”)深入挖掘错误的真正根源,并根据每个精确的案例执行不同的操作。可能有一两种情况会出现复苏,剩下的事情你无论如何都无能为力。(这在Java中是一个常见的问题,但它不只是例外;这并不是说以前没有人走过这条路。我喜欢Yegor Bugayenko关于Java中已检查异常的论点,基本上认为他偏爱的Java实践正是Swift解决方案。

This is not to say that there aren't cases where strongly typed errors would be extremely useful. But there are two answers to this: first, you're free to implement strongly typed errors on your own with an enum and get pretty good compiler enforcement. Not perfect (you still need a default catch outside the switch statement, but not inside), but pretty good if you follow some conventions on your own.

这并不是说没有强类型错误非常有用的情况。但是有两个答案:首先,您可以使用enum自己实现强类型错误,并获得相当好的编译器执行。不完美(在switch语句之外仍然需要一个默认的catch,但不是在内部),但是如果您自己遵循一些约定,就非常好了。

Second, if this use case turns out to be important (and it might), it is not difficult to add strongly typed errors later for those cases without breaking the common cases that want fairly generic error handling. They would just add syntax:

其次,如果这个用例是重要的(并且它可能是重要的),那么在这些情况下添加强类型错误并不困难,而不会破坏那些需要相当通用的错误处理的常见情况。他们只需要添加语法:

func something() throws MyError { }

And callers would have to treat that as a strong type.

打电话的人会把这当成一种强烈的类型。

Last of all, for strongly typed errors to be of much use, Foundation would need to throw them since it is the largest producer of errors in the system. (How often do you really create an NSError from scratch compared to deal with one generated by Foundation?) That would be a massive overhaul of Foundation and very hard to keep compatible with existing code and ObjC. So typed errors would need to be absolutely fantastic at solving very common Cocoa problems to be worth considering as the default behavior. It couldn't be just a little nicer (let alone have the problems described above).

最后,对于强类型错误的使用,Foundation将需要抛出它们,因为它是系统中最大的错误产生者。(与处理Foundation生成的NSError相比,您真正从头创建NSError的频率是多少?)这将是对基础的大规模改革,并且很难与现有的代码和ObjC兼容。因此,类型化错误必须在解决非常常见的Cocoa问题上非常出色,才能作为默认行为考虑。这是再好不过的了(更不用说上面描述的问题了)。

So none of this is to say that untyped errors are the 100% perfect solution to error handling in all cases. But these arguments convinced me that it was the right way to go in Swift today.

所以这并不是说非类型化错误是所有情况下错误处理的100%完美解决方案。但这些论点让我相信,这是如今迅速发展的正确方式。