Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Force unwrapping optionals is quite useful: it's great syntactic sugar for what often just gets rewritten as guard/assertionFailure.


That's so rare in practice that you should just write it out fully. If it's happening frequently in your app, you should probably rethink your architecture. As time goes on, I've realized why people think asserts are code smells of their own.


Do you not use implicitly unwrapped optionals for IBOutlets?


If you can prove it won’t be nil, normal IBOutlet included, fine.


That's about the only place for them to be acceptable, tbh.


We don't use storyboards or nibs.


That’s fine IF they can prove it won’t crash or that a crash is appropriate (a la forced exit). Too many developers use it as a happy path shortcut, not considering the compiler is warning of possible serious problems.

Crashes & exits are not acceptable in production code, and I’ve had to fix too many of them.


I strongly disagree. I would rather an application crashed and provided me with an actionable crash report rather than it continuing on in some random state. (This isn't to say that you should ignore errors; it's just that if you don't think there should be an error at a certain location, I would really want to know about it if there is one.)


That's why force-unwrap is so bad: the compiler is telling you there's a risk, at a time you can do something sensible about it, and force-unwrap puts solving the problem off to the worst possible scenario. My production user base can't afford "actionable crash reporting" as a debugging tool vs compiler warnings; even 0.01% of users experiencing it would get very expensive.


If a thing can’t be null/nothing and there is nothing you can do it’s usually best to tear the world down. Otherwise in the best case you have a button that does nothing but in the worst case something bad happens. In the normal case the crash just moves. “Catching” programmer errors because a program that limps along looks better than one that crashes is a design decision I never understood.


If "a thing can't be null/nothing", then you've made an error in making it an optional.

If a thing might be null/nothing but can't be used when it is, then you should write code that indicates your understanding of that case. Catching an error doesn't imply that your program should proceed, it communicates that you the programmer understood your system and anticipated its failure states. Proceeding or aborting is a secondary decision.


> If "a thing can't be null/nothing", then you've made an error in making it an optional.

I don't disagree with this, but I can point out gobs of places in AppKit where Apple has arguably 'made an error' and I can't do anything about it. Or in third-party C libraries, which hold 99% of the functionality I ultimately need, and were not designed for having nice Swift programming interfaces.

I feel like everyone saying "never force unwrap!" must be writing pure-Swift standalone functions, with no dependencies, including the operating system. The API for writing items to the Mac clipboard still documents that it can throw exceptions, which are impossible to catch in Swift!


Exactly. And in many languages that is quite difficult to ensure at compile time. In java all object parameters are by definition optoinal. Same thing in C# (before C#8 brought non-nullable types).

Obviously in F# or Haskell or C#8 or Rust this isn't a problem. But what we are talking about is: how do you handle, at runtime, in a language such as C#7 or Java, an null parameter being passed to a method that must return a value based on its parameter, but was passed null? It's a choice between very bad options where the least bad is usually to throw an ArgumentNullException or similar. Because there is nothing better to do.


> If "a thing can't be null/nothing", then you've made an error in making it an optional.

There are cases where the programmer cannot express this to the compiler without a bottom type.


It's not just that it looks better. It can give the person using the software a chance to save their data.


That one should always do of course (but perhaps not to the default place because there is every chance the data is already corrupted)


Yes, and I'm usually happy the compiler is there to warn me. However, the compiler is not great at telling me why something might fail, which can make it difficult to provide decent error handling. And of course, there are certain places where the compiler just cannot know that a certain operation will not fail.


That's why you use it only when you can prove it won't fail. I'm ok with that, and said so at the start.


I've inherited an Swift app once that was written by the dev for whom it was the first Swift project. IUOs everywhere. And the biggest contributor to the crash count. Spend six months cleaning it up; the crash rate went down dramatically. It is not wise some value will always be there when you do not control its source (e.g. API).


> I've inherited an Swift app once that was written by the dev for whom it was the first Swift project. IUOs everywhere.

Right, hence why I'm suggesting that they can be useful if you don't put them everywhere and aren't using them as a band-aid to make your code compile :)


A guard statement requires you to actually handle the error, though. The exclamation mark will crash the app.


assertionFailure is not any more "handling the error" than a forcefully unwrapping the optional.


Yeah, it's also something you shouldn't do.


What should you do when URL(string:) returns nil?


Obviously it depends heavily on what you're doing in your app and where that string is coming from.

Is it a hard coded string that will never change? Force unwrapping is probably appropriate.

Is it based on user input? Then you should probably tell the user the string they entered isn't a URL.


Right, and in that case it's pretty clear how errors can occur and what you should do to handle it.


That's contextual. Maybe some combination of:

- abort and unwind the current action

- retry something

- log something

- abort the app explicitly

- fallback to a different value

- comment why this is a known-possible failure state

- present a message to the user

...


The one time you should unwrap it is if it's a constant - that way the app will always immediately crash if it's nil. Pretty difficult to not run into a bug like that.

But if you're creating it dynamically you should be guarding and throwing an error.


Guard with assertionFailure and explanation for why it was used is much easier to notice and understand than !.


You know, I used to think that but I've come to realize that I often just ended up writing messages that were not useful. For example, here is some code that I wrote a while back:

  guard let data = notification.userInfo?["updatedItem"] as? Data else {
      assertionFailure("Could not retrieve updated item")
      return false
  }
I am really being helpful here? If I see a crash on this line:

  let data = notification.userInfo?["updatedItem"] as! Data
I get essentially the same information, except it's done in a less verbose and easier-to-discover way. Whereas the first one is like adding this kind of useless comment:

  let x = 5 // Assign 5 to x


Two problems I see:

1. ! used here is hard to spot, it's just few pixels of difference from ?.

2. assertionFailure is not the same as force unwrap, because it crashes only in debug mode. Ideally you would log it with some analytics so developers know if problem occured, but doing nothing is usually better than crashing the app.


Why not use `if let` instead? Way safer


The issue I'm talking about is what to do when you don't have a good idea of what to put in the "else" branch.


A usrful error message?


This isn't always possible.


Why not? I always fold or map my option types. Sometimes I return None and caller handles it, sometimes I print a useful and informative error message. One should never ever directly unwrap an option value. In fact, some languages and libraries simply don’t allow it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: