[swift-evolution] Remove Failable Initializers
Félix Cloutier
felixcca at yahoo.ca
Fri Mar 4 17:07:29 CST 2016
Saying that the optimizer will *probably* make it okay is a very poor justification for replacing a fast feature with a slow one.
I would like to remind that this proposal amounts to you going into my code, and everyone else's code, and break it.
You would certainly not like me to go into your code and break it, unless I had an excellent reason to do it.
However, so far, I don't see any technical merit to it. It's not faster, it's not shorter, it's not better error handling. And even if you think that you can say that it's not worse, you so far have stopped short of showing that it's better. Can it be faster? Don't think so. Can it be shorter? Don't think so.
This is mostly just enforcing a programming style you believe in to the whole Swift community, without regards to whether the rest agrees with it.
Félix
> Le 4 mars 2016 à 17:42:06, Haravikk <swift-evolution at haravikk.me> a écrit :
>
>
>> On 4 Mar 2016, at 16:32, Félix Cloutier <felixcca at yahoo.ca <mailto:felixcca at yahoo.ca>> wrote:
>>
>> If anything, the fact that NSImage doesn't respect the error handling guidelines is an argument in favor of reworking the NSImage interface, not doing away with the guidelines. All (I think?) of the Foundation class initializers accept an inout error parameter, which translate to throws in Swift.
>
> True, but even when you’re writing a type in pure Swift from the start, once you have a failable initialiser it can be easy to just return nil when you think of other possible error conditions that didn’t occur to you sooner (I did this a couple of times myself before try? was added and I switch to error handling only). While someone might do the same with an InvalidArgument error type, as long as it can take a message it’s trivial to customise each unique error that your initialiser/method can produce.
>
>> Consider reading Joe Duffy's writeup on error handling in Midori <http://joeduffyblog.com/2016/02/07/the-error-model/#ambitions-and-learnings> which presents "abandonments" (what I think failable initializers model best) and actual exceptions (what I think throwing models best).
>
> It’s definitely an interesting article but there are a few drawbacks listed to exceptions that I’d like to go over:
>
>> 1. Exceptions are used to communicate unrecoverable bugs, like null dereferences, divide-by-zero, etc.
>
>
> This is really a matter of convention, and also more of a matter of terminology. For example, in Swift, they’re just errors rather than exceptions; i.e- there’s no strict indication of their severity, and like any good “exception” model it’s up to the developer if they want to throw an error onwards, silently hide it, do some recovery etc. If you wish to throw a minor error vs a severe one, then you use different error types and document what they represent.
>
> I’d also argue that a failable initialiser represents no less severe an issue than an error does, as the initialiser has still failed, and therefore created nothing usable, ultimately requiring some form of recovery (testing for nil, supplying a default etc.). It isn’t clear at all to me that these are different things, as both can be recoverable or unrecoverable depending upon which form you use it in (try? vs try! vs try/catch, or Foo() vs Foo()!).
>
>> 3. Although signatures declare exception types, there is no indication at callsites what calls might throw.
>
>
> This of course isn’t an issue in Swift, as the try keyword is mandatory. Thanks to try? and try! this also eliminates number four (everybody hates exceptions) which is largely a complaint about having to build try/catch blocks around them, but with try? and try! we can easily eliminate that when we know we don’t need any extra information besides whether or not a failure occurred.
>
> Also, regarding overhead of exceptions, I still think that this is something that can be optimised away. All the compiler has to do is identify throw statements, and isolate code specific to them (i.e- variables etc. that are only used as part of a throw); now when you call a method/initialiser with try? or try!, any code identified as being part of the throw can be skipped as all that’s needed is a binary flag (threw vs. succeeded). Of course it sounds a bit easier than it is in reality, but I’m pretty sure it should be possible to change behaviour depending upon how the code is called (i.e- whether an error will actually be used, or simply ignored in favour of its status). When debugging of course the error can be returned in all cases so we can generate and see it.
> In short, with Swift’s ability to explicitly declare whether we want an error returned vs simply knowing that an error occurred, it should be possible to optimise such that it is just as efficient as a failable initialiser (if not more so, since the return value isn’t an optional).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160304/cba53c2a/attachment.html>
More information about the swift-evolution
mailing list