[swift-evolution] Preconditions aborting process in server scenarios [was: Throws? and throws!]

Xiaodi Wu xiaodi.wu at gmail.com
Tue Jan 17 20:10:22 CST 2017


On Tue, Jan 17, 2017 at 6:50 PM, Jonathan Hull <jhull at gbis.com> wrote:

> 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.
>

So, again, your particular problem isn't about whether Swift lets you
handle errors in a certain way--it already does. Your objection is about
the spelling.


> 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:
>

You already have the option of making this work for you _exactly_ as you
like:

```

enum ArithmeticError : Error {

  case add, multiply, subtract, divide

}


infix operator &&+ : AdditionPrecedence

infix operator &&- : AdditionPrecedence

infix operator &&* : MultiplicationPrecedence

infix operator &&/ : MultiplicationPrecedence


extension Int {

  static func &&+ (lhs: Int, rhs: Int) throws -> Int {

    let (result, flag) = Int.addWithOverflow(lhs, rhs)

    guard !flag else { throw ArithmeticError.add }

    return result

  }

}
```

This requires absolutely no redesign of Swift error handling. You can even
customize how fine-grained the error messages are.

By contrast, I think the present topic of this thread--identifying ways in
which a logic error might bring down only a single process, or whether
that's even a desirable thing--is a sorely needed discussion which will
require deep support baked into the compiler.


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> wrote:
>
>> On Jan 17, 2017, at 1:38 PM, Dave Abrahams via swift-evolution <
>> 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
>> 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/0a9710e3/attachment.html>


More information about the swift-evolution mailing list