Over at Human Friendly there is a blog post about needing an
!!. I get what is being said: you have an
Optional that shouldn’t be
nil (it’s an
Optional for many reasons, typically outside of your control such as a bridged item from ObjC). Sounds reasonable, after all, no one likes crashing apps and the alternative is to use the
if-let form to handle the case (or the shorthand
So instead of writing this:
assert(opt != nil) let foo = opt ?? safeValue
You use the shorthand version:
let foo = opt !! safeValue
Sure, it’s more terse. However, and this is the main reason I do not like this pattern: it is introducing a class of bugs that Swift has intentionally chose to make hard to get into and the very reason some are choosing to rewrite everything in Swift.
We did indeed see surprising patterns in the causes of these bugs. I found myself repeatedly saying to myself or Janie that a particular bug wouldn’t have even compiled under Swift, or would have thrown an immediate exception. When we totaled up bugs like this, we found that 40% of bugs shipped to customers in the last three years would have been caught immediately by using Swift. The primary classes of these bugs were:
- Silent failures due to nil-messaging (emphasis added)
- Improperly handled NSErrors, or other Objective-C error failures
- Bad object typecasts
- Wrong enum lookup tables being used for values
This operator is introducing the same exact semantics that some are trying to run away from.
opt is never supposed to be
nil, then do an
assert on it and log those errors using some sort of telemetry system or simply force unwrap it. The crash logs will help you find these issues and fix them, silently failing will not get you that information.
And you won’t find these issues in testing when using
assert unless you also test against
debug builds. If you are testing
debug builds instead of
release builds, then you really are not testing the product you’ll be giving your customers… but that’s a topic for another day.