I’m a +1.
The strength of the resistance to it puzzles me a bit. This is a low-burden proposal, both in language surface and implementation. It’s good for both (1) code readability and (2) runtime diagnostics in the wild; either would be sufficient to justify it. The utility-to-burden ratio is high.
Examples of usage in practice
Concrete examples are helpful. Here are a few from actual code.
Here the code needs a non-nil URL that is valid, but will always generate errors if anyone attempts to load it:
url = URL(string: ":")!
It is possible that this dubious assumption about :
passing syntactic muster as a URL might change with a future version of Foundation. If it does, this once-working code will suddenly fail in production with a bollixing crash — hopefully traceable back to the offending line, but we all know how tenuous that can be in practice.
Imagine, however, that we have the !!
idiom to follow:
url = URL(string: ":") !! "A single colon is a valid URL for which all requests fail"
Now the underlying assumption is documented in the code, and the runtime error we get if Foundation shifts underneath our feet is much more useful: “Fatal error … blah blah … Assumption failed: A single colon is a valid URL for which all requests fail.”
The !!
operator improves both readability and debuggability.
(There’s a debate to be had about whether the message should be phrased as the positive assumption whose failure is an error, or as a description of the theoretically impossible error. I prefer the former, as above, because it reads better as documentation.)
Here’s another example, where the assumption underlying the force unwrap is less localized and thus less obvious:
return request(method,
data: urlEncodedParams.data(using: String.Encoding.ascii) !! "A URL-escaped string is already ASCII",
contentType: "application/x-www-form-urlencoded",
requestMutation: requestMutation)
In this second example, in my actual code, I have the same message in a comment:
return request(method,
data: paramString.data(using: String.Encoding.ascii)!, // Reason for !: A URL-escaped string is already ASCII
contentType: "application/x-www-form-urlencoded",
requestMutation: requestMutation)
Making this information (1) part of a standard idiom and (2) surfacing it at runtime both seem preferable to the ad hoc comment.
Versus more generalized proposals
I like the idea of Never
being a true bottom type; however, that’s a large and complex question, and there’s no reason to hold up this simple proposal to support in it. In the future, the proposed !!
operator could just be sugar for it; this proposal does not harm a hypothetical bottom type.
However, I do not like the idea of ?? fatalError("…")
instead of !!
. Why? For the same reason I like have the !
operator: concise, idiomatic clarity. Code using these operators assumes it is impossible for a particular unwrapping to fail (or at least that a failure is reason enough to terminate the whole process). This is a fatal error, and there is no need for spelling out a recovery path; the only question is whether the underlying assumption is worth documenting in each particular instance. Spelling out ?? fatalError("Assumption failed: …")
is just information-obscuring boilerplate.
Note how the more verbose syntax harms both readability and ergonomics in my examples above:
url = URL(string: ":") ?? fatalError("Assumption failed: A single colon is a valid URL for which all requests fail")
// vs
url = URL(string: ":") !! "A single colon is a valid URL for which all requests fail"
return request(method,
data: urlEncodedParams.data(using: String.Encoding.ascii)
?? fatalError("Assumption failed: A URL-escaped string is already ASCII"),
contentType: "application/x-www-form-urlencoded",
requestMutation: requestMutation)
Yes, it’s more explicit. No, it’s not more readable. This extra syntax is enough burden to harm adoption in practice; presented with this option or !
, developers will be much more likely to choose the bare, message-less force-unwrap.
The concise !!
syntax, on the other hand, presents no more burden than a //
comment followed by the same message. It draws attention immediately to the information-bearing text.
Despite the long argument above, I don’t have fiery feelings about this proposal. But it seems sensible and useful. Like I said, the utility to burden ratio is high — higher than many extant features.