On Thu, Jan 12, 2017 at 6:27 PM, Jonathan Hull <[email protected]> wrote:
> The problem with Java (and ObjC) is that exceptions can propagate > unexpectedly into scopes which they weren’t expected and you end up with > objects in inconsistent states where it is nearly impossible to continue in > any meaningful way. That can’t happen here as the error will never > propagate beyond where it is expected to be. On the contrary, ‘throws!’ > and ‘throws?’ both stop the propagation earlier than ‘throws’. > That's a fair point about `throws!`. It seems that your motivation for `throws!` is to avoid writing `try!` at the call site, since the functionality is otherwise the same. That keyword, notably, is required at most once per statement. So--unless you're trying to build up a solution for a whole new category of error (as mentioned above)--the question boils down to: does having to write `try!` offer four letters' worth of benefit at the call site? Your answer, if I understand, seems to be: sometimes it might not be worth four letters, and that should be enough to justify a new feature. I think, to make a convincing case, you'll have to offer real-world use cases where many can agree on that point, sufficient to justify the engineering resources for such a feature. IMO the mere possibility that such a use case may exist is not enough, especially offset against what I would argue is a real benefit to readers of code that every call to a throwing function is currently clearly annotated. As to `throws?`, I'm not sure quite sure how it is supposed to work. If a function `throws? -> Int`, is the return value actually of type `Int?`? And if it's `throws? -> Int?`, then is the return value actually of type `Int??`? In what ways would this design be superior to the already sketched out `Result<T>` type outlined in the Error Handling Rationale document, which several people on this list have lined up to propose? Would a `Result<T>` cover even your use cases for `throws!`? Also, ‘try’ is still required to explicitly mark a potential error > propagation point, which is what it was designed to do. You don’t have > ‘try’ with the variants because it is by default no longer a propagation > point (unless you make it one explicitly with ’try’). > If this is quite safe and more convenient, why then shouldn't it be the behavior for `throws`? (That is, why not just allow people to call throwing functions without `try` and crash if the error isn't caught? It'd be a purely additive proposal that's backwards compatible for all currently compiling code.) Thanks, > Jon > > On Jan 12, 2017, at 3:50 PM, Xiaodi Wu <[email protected]> wrote: > > Some additional thoughts: if I recall correctly from my (limited) Java > days, throwing in Java worked essentially like your proposed `throws!`. > That the Swift model expressly deviates from that example was not by > accident, as far as I can tell. According to the error handling docs in the > Swift repo: > > "Once an error is thrown, Swift will automatically propagate it out of > scopes (that permit it), rather than relying on the programmer to manually > check for errors and do their own control flow. This is just a lot less > boilerplate for common error handling tasks. However, doing this naively > would introduce a lot of implicit control flow, which makes it difficult to > reason about the function's behavior. This is a serious maintenance problem > and has traditionally been a considerable source of bugs in languages that > heavily use exceptions. > > "Therefore, while Swift automatically propagates errors, it requires that > statements and expressions that can implicitly throw be marked with the > `try` keyword." > > So I think what this is saying is that requiring `try` _every time_ is > core to the design of Swift error handling, and that `throws!` or even > `throws?` would undo it. > > > On Thu, Jan 12, 2017 at 5:35 PM, Xiaodi Wu <[email protected]> wrote: > >> On Thu, Jan 12, 2017 at 4:58 PM, Jonathan Hull via swift-evolution < >> [email protected]> wrote: >> >>> I really like swift’s error handling system overall. It strikes a good >>> balance between safety and usability. >>> >>> There are some cases where it would be nice to throw errors, but errors >>> are rarely expected in most use cases, so the overhead of ‘try’, etc… would >>> make things unusable. Thus fatalError or optionals are used instead. For >>> example, operators like ‘+’ could never throw because adding ’try’ >>> everywhere would make arithmetic unbearable. But in a few cases it would >>> make my algorithm much cleaner if I just assume it will work and then catch >>> overflow/underflow errors if they happen, and resolve each of them with >>> special cases. Or perhaps I am dealing with user entered values, and want >>> to stop the calculation and display a user visible error (e.g. a symbol in >>> a spreadsheet cell) instead of crashing. >>> >> >> Unless I'm mistaken, there is a performance overhead for throwing >> functions, and thus a much greater barrier to the use cases outlined above >> is that the performance penalty for '+' would be unacceptable in any case, >> whatever syntactic sugar you could come up with. >> >> >>> I would like to propose adding ‘throws?’ and ‘throws!’ variants to >>> ‘throws’. >>> >>> These would be used for cases where error handling is not the default >>> desired behavior, but having it as an option is desired occasionally. >> >> >> While I admit the idea has an appeal on a practical level, I have an >> uncomfortable feeling about this. It's by definition true that error >> handling is never the default desired behavior, and if I recall correctly >> the performance of Swift error handling is tuned on the assumption that not >> throwing is far more common than throwing. If we accept this statement at >> face value as the justification for including `throws!`, then essentially >> all `throws` should be `throws!`. And indeed I suspect that if the feature >> were be implemented, that would rapidly become the case in much written >> Swift. In essence, then, I think you're effectively proposing to invert the >> assignment of responsibility for determining how errors are handled from >> the call site to the declaration site, at least by default. It goes against >> an overarching design principle in Swift (discussed earlier in the thread >> about DefaultConstructible) not to provide such defaults and to require >> explicitness at the call site. >> >> Essentially, the user would no longer have to preface the call with >>> ‘try’, as the compiler would implicitly add ‘try?’ or ‘try!’ respectively. >>> >>> Thus, the function would act like a non-throwing function (either >>> trapping or returning an optional in the case of error), but the user could >>> add ‘try’ to the call to override that behavior and deal with the error >>> more explicitly. >>> >>> Another example would be bounds checking on arrays. If subscripting >>> arrays was marked as ‘throws!’ then it would have the same default behavior >>> it does now (trapping on bounds error). But a user could add ‘try?’ to >>> return nil for a bounds error in cases where they explicitly want that, or >>> they could add ‘try’ to deal with it as an error using do-catch. >>> >> >> Subscripts cannot throw at all at the moment, and in another thread some >> of the challenges for designing throwing subscripts were just mentioned. I >> suspect any sort of throwing subscript will not be possible in the >> immediate future, so the argument for `throws!` here is moot. >> >> I think this would really increase the availability of error handling in >>> areas where it is impractical right now… >>> >> >> I think the practical argument could be made stronger by use cases not >> encumbered by other difficulties as outlined above. Is there a currently >> throwing function you've encountered that would be greatly improved by such >> a feature? Besides that, though, my discomfort is (as mentioned above) that >> the practical effect of such a feature is that it will actually altogether >> invert the default responsibility for error handling, and I'm not sure that >> it's entirely consistent with Swift's design as a consequence. In any case >> it'd be a far greater change than you've made it out to be. Interesting >> suggestion, definitely. >> >> Thanks, >>> Jon >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> >> >> > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
