[swift-evolution] Preconditions aborting process in server scenarios [was: Throws? and throws!]
Jonathan Hull
jhull at gbis.com
Tue Jan 17 18:50:39 CST 2017
I rewrote some code which used NSDecimalNumber to use Decimal and it went from 20 lines of hard to follow code to 2 lines of easy to follow expressions. ‘2+2’ is much easier to understand at a glance than having a sentence for each operation.
Also the control flow is completely different. With one, you have try and then a full equation, and you catch and handle different cases if something went wrong (overflow, underflow, divide by zero). With the other you have to have a guard AFTER each line which uses a previous result (or a pyramid of doom), potentially repeating the same error handling code over and over:
let (a,o1) = Int.addWithOverflow(x,y)
guard o1 == false else {throw MyError}
let (b,o2) = Int.multiplyWithOverflow(a,z)
guard o2 == false else {throw MyError}
let (c,o3) = Int.subtractWithOverflow(b,z)
guard o3 == false else {throw MyError}
return c
vs:
do{
return try ((x+y)*z)-z
}catch _ {
throw MyError
}
Thanks,
Jon
> On Jan 17, 2017, at 4:22 PM, Xiaodi Wu via swift-evolution <swift-evolution at swift.org> wrote:
>
> We already have three ways of handling integer overflow:
>
> + traps
> &+ overflows
> addWithOverflow overflows and sets a flag if it does so
>
> This supports all possible ways of handling the issue: you can trap, you can get a result and not care about the overflow flag, or you can get the result *and* the overflow flag. You can even discard the result and work with only the flag.
>
> I don't see how this doesn't meet exactly what you and Jonathan Hull describe: it is opt-in, optional for callers, and does not propagate. It doesn't require try or any other cumbersome syntax, and it allows you to just compute the operation first and handle the overflow later only if it occurs.
>
> For array indexing, there is an outstanding proposal for more lenient subscripts. In the meantime, you can trivially implement your own. Such a facility would also behave according to your stated requirements.
>
> On Tue, Jan 17, 2017 at 18:03 David Waite via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> On Jan 17, 2017, at 1:38 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>> It also means, from a purely pragmatic view, that control flow for
>> things that are really not reliably recoverable conditions (like index
>> out-of-range) is not cleanly separated from control flow for handling
>> recoverable things like dropped network conditions, so it can be really
>> hard to know that you're reliably shutting down the program when you
>> should, and that's not being subverted by some general “recovery” code.
>
> Agreed. The “try” syntax is part of a decision to use errors to represent conditions recoverable by business logic. This might be a network connection closed, but shouldn’t be used for conditions like memory allocation failed, a KILL signal, or detection of corrupted data within an application bundle.
>
> In the middle are avoidable runtime errors like array indexing out-of-bounds and math overflow. Some business logic might care about these, in particular logic which deals with arbitrary user input. However, using ‘try’ syntax would result in both an explosion of needing to specify try in expressions, and in errors which can’t really be recovered in typical business logic.
>
> I see this as three regions of error conditions - system level errors that the developer isn’t expected to try and recover from, application-level errors that the developer is likely going to want to control the behavior of, and in between the runtime errors which some logic might care about, but which in most cases should be treated as a system level error.
>
> Java roughly has Error, Exception, and RuntimeException to correspond to these, with a few differences which I generally consider to be flaws in the Java language (RuntimeException is under Exception, RuntimeExceptions percolate up the entire stack rather than being escalated to Errors if unhandled).
>
> I can envision a future state where:
> - system level errors can have atexit/terminate-style shutdown hooks. These do not support recovery, but can be used to attempt a cleaner shutdown
> - functions which emit runtime errors (such as math overflow) can support a call form which returns an error rather than precondition failure, but it is opt in and optional for callers. The runtime errors do not propagate automatically, and callers which do not request it get precondition failures
> - the possibility of containerization so that runtime errors and certain system level errors terminate a thread/actor/app domain rather than the whole process
>
> -DW
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170117/02c64fd8/attachment.html>
More information about the swift-evolution
mailing list