5 ms·
Pure Swift now. It wasn't viable as v1, but now it's solid & clean. Seems like it was a good opportunity to take a well understood language (C/C++/Obj-C) and
by ctdonath 7y ago
Pure Swift now.
It wasn't viable as v1, but now it's solid & clean.
Seems like it was a good opportunity to take a well understood language (C/C++/Obj-C) and after 30 years rebuild it ground-up into what it should be. Some constructs & workarounds just weren't going away without a clean-slate industry-wide fully-compatible restart.
Top problem now is getting developers to not force-unwrap optionals unless unless able to prove it won't cause a crash.
- zapzupnz 7y agoEven when they can prove it, they shouldn't do it. It's not hard to conditionally unwrap optionals.
- saagarjha 7y agoForce unwrapping optionals is quite useful: it's great syntactic sugar for what often just gets rewritten as guard/assertionFailure.
- ctdonath 7y agoThat’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.
- saagarjha 7y agoI 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.)
- ctdonath 7y agoThat'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.
- saagarjha 7y agoYes, 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.
- ctdonath 7y agoThat'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.
- alkonaut 7y agoIf 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.
- swatcoder 7y agoIf "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.
- untog 7y agoA guard statement requires you to actually handle the error, though. The exclamation mark will crash the app.
- saagarjha 7y agoassertionFailure is not any more "handling the error" than a forcefully unwrapping the optional.
- untog 7y agoYeah, it's also something you shouldn't do.
- saagarjha 7y agoWhat should you do when URL(string:) returns nil?
- RandallBrown 7y agoObviously 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.
- saagarjha 7y agoRight, and in that case it's pretty clear how errors can occur and what you should do to handle it.
- untog 7y agoThe 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.
- AJRF 7y agoWhy not use `if let` instead? Way safer
- saagarjha 7y agoThe 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.
- mruts 7y agoA usrful error message?
- saagarjha 7y agoThis isn't always possible.
- mruts 7y agoWhy 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.
- novok 7y agoThat'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.
- krzat 7y agoGuard with assertionFailure and explanation for why it was used is much easier to notice and understand than !.
- saagarjha 7y agoYou 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
- krzat 7y agoTwo 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.
- ntumlin 7y agoSimilarly in Typescript, it seems like most of my code reviews consist of just telling people not to override null checking. Adding a ! suppresses an error from the compiler, it doesn't fix an error in your code!
- raverbashing 7y agoThat's an interesting discussion, and one that will still keep happening. At a given point, you can handle errors, but there's nothing you can do about them It's good when languages (and developers) realize there are errors you should handle but there are errors you "shouldn't" because there's nothing you can do but bail out.
- ctdonath 7y ago"Nothing to do but bail" is very rare, orders of magnitude below the frequency of misused force-unwrap.
- donarb 7y agoI save force unwraps for things that will be caught at develop/testing time, like app images that are supposed to be in the binary or controls that are supposed to be wired up in Interface Builder. Otherwise, for me, using a force unwrap is a code smell.
- swatcoder 7y agoIn almost all cases, there's a more appropriate way to indicate your expectations than using force-unwrap. Even in those cases where you can't recover from a failure of those expectations, your code will be 1000x more legible if you demonstrate that you understand that the error could exist and what it might represent about the system as a whole. If you want to explicitly fire a fatal error after that because there's no other form of recovery, so be it. Trying to capture all that in a "!" saves you a few LOC (or worse: minutes of reasoning) now but suggests somebody else might be pulling their hair out in frustration six months later. Please don't do that to someone.
- 7y ago
- novok 7y agoYou fix that by banning force unwraps outside of something like unit tests with a linter. We do it at work and I can't remember it ever being an issue.