[swift-evolution] [Pitch] Introducing the "Unwrap or Die" operator to the standard library

Elviro Rocca retired.hunter.djura at gmail.com
Thu Jun 29 07:23:52 CDT 2017


> Well, a persisted inconsistency is worse than a crash :P

I still strongly disagree with this, I'm sorry. Inconsistent data is an orthogonal problem to fatal errors, and a crash is basically a middle finger to the user. 

> To me this !! operator does not add enough value to put it in the standard library. The existing force unwrap operator already works fine, and if Never is really going to be a bottom type, then I don't know in which cases the !! operator would be better.
> 
> Actually, for me it would be worse, because you could only call it with a String or a function that returned a String. What happens if I want to call a method that does some housekeeping and then ends with a fatalError? I could not use the !! operator unless that method returns a String.
> 
> And finally, I would not want to find such code in a project with multiple people involved, as my personal experience is that a single ! leads to crashes in production sooner or later, and if you track such crashes it would not be obvious why they happen. If that code is written by one person and will not be published anywhere, I suppose you can use it, but either in open source projects or in teams, I would avoid that operator like hell.
> 
> Instead of writing this (the original example, which by the way has a typo :P):
> 
> guard !lastItem.isEmpty else { return }
> let lastItem = array.last !! "Array must be non-empty"
> 
> I would just write this:
> 
> guard let lastItem = array.last else { return }
> 
> The first example seems reasonable enough: you know that the array is empty, you just checked for it! But that array may possible be a property of a class and it can be changed in another thread, so you can't be so sure. And because software is usually never finished, some other team mate can add more code between the first line and the second line, making it easier to inadvertently change the array contents and thus not preserving the initial invariants. The second example may need to be rewritten if the requirements change, but it does not have the same drawbacks as the initial example and, well, it's definitely less code and easier to read.
> 
> Anyway, can we provide a real world example? If some projects are already defining this operator, working examples must exist and we can analyze how this operator affects the code and which patterns are leveraged by it.
> 

I agree with most of this, but I think the contraposition here is with:

guard let lastItem = array.last else { fatalError() }

> I understand your wish to never crash in production. But I think it’s an ideal that is quite far from the day to day development practices of many developers. If the philosophy of the Standard Library was to avoid all production crashes, we wouldn’t have the following:
> 
> Implicitly unwrapped optionals
> Optional explicit unwrapping
> fatalError
> precondition
> 
> The fact is that we have those tools and that they are useful and used. I salute your wish to ban all of the above in an effort to avoid all crashes in production, but IMHO, it’s a style that is best enforced using a linter.

Swift is a language that doesn't enforce a particular style over the other (thankfully) so the standard library includes many constructs that can end up being mostly ignored by some people in some projects.

Because of that, I don't think that we should add to the standard library a particular construct just because some people use it in third party libraries, if the same behavior can be already accomplished with very minimal code using what's already there.

Also, avoiding all crashes in production is to me a fundamental value of software development, and is not particularly related to Swift or iOS or whatever. In fact, as was already written some posts before, logic errors are either mistakes or are used to avoid additional checks in cases when the overhead introduced by those checks is not acceptable from a performance standpoint, which is a very unfrequent case.

Now, during development I can decide to make something crash for informative reasons, so in general I'm not opposed at all to those constructs, but that doesn't justify production code that crashes due to implicit unwrapping or out-of-bounds errors. That's my opinion, and it's also my opinion that trusting a linter is a much weaker solution than actually enforcing the type-system and the compiler, and I'd say that Swift is not Objective-C or PHP, but that's a completely different topic.

Elviro

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170629/639a436d/attachment.html>


More information about the swift-evolution mailing list