-1

I've already read Difference between “precondition” and “assert” in swift. But still can't draw a clear line between the (different ways of unwrapping ie guard & ! + error handling) vs assertions.

If I want my application to no longer work, can't I just force unwrap something and substitute as for a precondition?

  1. Is it because we want to stop/exit the app and basically don't want any control flow or state changing and therefore we use asserts/preconditions which also happens to come with easy logging of human readable messages (helps us to not constantly write prints)?
  2. Things that we use asserts for have are vital, guard statements are eventually a control flow system that even if your function returns early doesn't necessarily mean your app should crash.

And if it's anything beyond nils like you want a String and the user is giving you an Int then you can use error handling.

EDIT:

I'm not after opinions, I'm asking this only to understand what convenience assertions provide over the mentioned alternatives. The numbered list is the core of my question.

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • FYI - using `if let` is the opposite of "force unwrapping" (which is using `!`). – rmaddy Feb 24 '17 at 15:50
  • @rmaddy fixed. Thanks – mfaani Feb 24 '17 at 15:53
  • I think this ultimately comes down to coding style, which is primarily opinion-based. – JAL Feb 24 '17 at 16:00
  • 2
    @JAL I'm **not** asking about coding style. I just want to understand the difference of (assertions vs. guard + forced unwrapping + error handing). And be able to use from what Apple has provided. But it seems that you approve the differences that I see, right? That's all I want to know. – mfaani Feb 24 '17 at 16:05
  • You also realize that `assert` and `precondition` can be used without optionals right? You can assert any boolean condition, not just if a value is `nil`. If you google "when to use asserts" you'll see a bunch of discussions on the topic. It's language agnostic. – JAL Feb 24 '17 at 16:12
  • 1
    @JAL Thanks, I just read some of them, but that's really not my question. My question is : For the places where you can use asserts, why not instead use (guard + forced unwrapping + error handling)? – mfaani Feb 24 '17 at 16:27
  • I see no good reason to use `assert` when one could use `guard` and the other modern features Swift provides. It's possible that a legacy programmer who does not know all of the features Swift provides will fall back on using asserts, but I don't find that very Swifty at all. But again, this is all style and up to the programmer. – JAL Feb 24 '17 at 16:31
  • 1
    @JAL Is there any scenario where assert can do things easier or simply can do things that the other alternatives **can't** do? – mfaani Feb 24 '17 at 16:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/136565/discussion-between-jal-and-honey). – JAL Feb 24 '17 at 16:35
  • 2
    @Honey Well yes, `assert`s will be removed in -O builds (as the linked Q&A says), while the other options you mention won't (they'll remain in production code, although `!` won't check for `nil` in -Ounchecked builds) – thus making it good for sanity checking values during debugging. – Hamish Feb 24 '17 at 16:37
  • 3
    IMO: `assert` and `precondition` are for detecting state which is so unusual and unexpected that you can't really handle it, and maybe you don't want to handle it because it's indicative of something very wrong like stack or heap corruption. BTW, forced unwrapping itself is vaguely equivalent to `func forceUnrwap(thing: T?) -> T { guard let thing = thing else { preconditionFailure() }; return thing }` so there's that. But like people have mentioned it's a stylistic thing like tabs vs. spaces or linefeed-curly-brace. – joeybladb Feb 24 '17 at 16:40

1 Answers1

3
  • Errors are a form of flow control, on a par with if and while. In particuar, they involve coherent message sending and early exit. The idea is to wind up the current scope immediately and return control to the caller, telling the caller "something went wrong".

  • Assertions are a way to crash immediately.

Thus they belong to completely different conceptual worlds. Errors are for things that can go wrong in real time, from which we need to recover coherently. Assertions are for things that should never go wrong, and about which we feel so strongly that we don't want the program even to be released into the world under these circumstances, and can be used in places where Errors can't be used.

Example from my own code:

final class Board : NSObject, NSCoding, CALayerDelegate {
    // ...
    fileprivate var xct : Int { return self.grid.xct }
    fileprivate var yct : Int { return self.grid.yct }
    fileprivate var grid : Grid // can't live without a grid, but it is mutable
    // ...
    fileprivate lazy var pieceSize : CGSize = {
        assert((self.xct > 0 && self.yct > 0), "Meaningless to ask for piece size with no grid dimensions.")
        let pieceWidth : CGFloat = self.view.bounds.size.width / (CGFloat(self.xct) + OUTER + LEFTMARGIN + RIGHTMARGIN)
        let pieceHeight : CGFloat = self.view.bounds.size.height / (CGFloat(self.yct) + OUTER + TOPMARGIN + BOTTOMMARGIN)
        return CGSize(width: pieceWidth, height: pieceHeight)
    }()
    // ...
}

If pieceSize is ever called with a zero grid dimension, something is very wrong with my entire program. It's not a matter of testing for a runtime error; the program itself is based on faulty algorithms. That is what I want to detect.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1. This line `assert((self.xct > 0 && self.yct > 0)` is uncrashable—with forced unwrapping, guards, errors. right? Only thing I can do is use `fatalError()` which is a form assertions. 2. I *can* crash with forced unwrapping for `nil`s but that won't allow me to log messages. right? – mfaani Feb 24 '17 at 17:08
  • What's to unwrap? How would a guard help? How would you throw an error here? I state directly what I am assuming is true, `self.xct > 0 && self.yct > 0`, and I crash if I'm wrong. What could be better? – matt Feb 24 '17 at 17:12
  • Isn't your question similar to "Why use `for...in` when we can always unroll to a `while` loop and an iterator?" If you don't want convenient, appropriate high-level language features, why not program in assembly language? – matt Feb 24 '17 at 17:14
  • Oops yes too much of optionals in my head....My question was 1. is the difference the convenience? Which your answer is Yes/No. Your 2 bullets put a great *functional* contrast for their usage. Yet with optionals perhaps it's a matter of convenience. 2. Are there any areas where it's no longer a convenience but a must as in the alternatives simply can't do what's intended. – mfaani Feb 24 '17 at 17:17