[swift-evolution] Preconditions aborting process in server scenarios [was: Throws? and throws!]
alblue at apple.com
Tue Jan 17 05:28:54 CST 2017
> On 17 Jan 2017, at 11:10, Jeremy Pereira via swift-evolution <swift-evolution at swift.org> wrote:
>> On 17 Jan 2017, at 02:38, thislooksfun via swift-evolution <swift-evolution at swift.org> wrote:
>> I really hate to bring Java up, but I really do think it got at least one thing right with its error system, namely that one subset of error (namely `RuntimeException`), wouldn't be enforced by the compiler, but could optionally be caught.
> I don’t entirely agree for two reasons:
> 1. If a runtime error is thrown and caught, there is no way to guarantee the logical consistency of the state of the running process because who knows which stack frames were unwound without cleaning up properly. There is no way to safely catch a run time exception and recover.
From a Java perspective, clearly that's not true.
It may well be true for the current implementation of Swift, and there's questions about how to clean up objects with reference counts outstanding (since there's no garbage collector). It isn't necessarily the case that it isn't possible, but it does require some additional stack unwinding; and the implementation of that may be too cumbersome/impractical/undesirable to occur.
> 2. People abuse RuntimeException to simplify their error handling code: “if I throw a RuntimeException I don’t need a zillion catch clauses or throws declarations”. Furthermore, if a library uses RuntimeExceptions where it should be using Exceptions there is no way to know if its API has changed except by reading the (hopefully up to date) documentation.
> Problem 2 makes me particularly bitter because JEE programmers seem to have learned that allowing code to throw null pointer exceptions has no real consequences for them so they become very cavalier about doing their null checks. The user sees an 500 error page, the sys admin gets a 200 line stack trace in the log, but the system carries on. If you are lucky enough to have the source code to diagnose the problem, it usually turns out that the exception was thrown on a line with eight chained method calls. When you do track the problem down, it turns out you forgot a line in the properties file or something similar but the programmer couldn’t be bothered to help you out because it was easier just to let the null pointer exception happen.
That's a pretty poor example, and in any case, the individual cause would allow the system to continue on processing subsequent requests, which is generally what's wanted. When you're working on large systems and with large data sets, there are generally always problematic items like this which have to be diagnosed sufficiently in order to be retried, or even handled manually. It has very little to do with the language and more to do with the quality of data which isn't something you always have control over.
> I like Swift’s error handling because programming errors (like force unwrapping nil) are punished mercilessly by process termination and errors caused by external factors cannot be completely ignored. You have to at least put an empty catch block somewhere.
This is one of the significant problems in Swift at the moment for server-side logic. It may make sense to do this from a single-user application, but writing a server which is designed to handle hundreds or thousands of simultaneous clients can suffer from the fact that one bad client request can take out everyone's connection. In the server working group and in existing tools like Kitura/Vapor/Perfect etc. it's a non-trivial problem to solve, other than using a CGI like model where each request is handled by a single worker process that can terminate independently of the other requests in flight.
More information about the swift-evolution