#assertfailure
Explore tagged Tumblr posts
Text
7 Common Mistakes When Using Assert for Debugging
Using assert for debugging often leads to pitfalls: 1. Overuse without clear checks; 2. Neglecting side effects in assert conditions; 3. Assuming asserts are for user input validation; 4. Failing to handle assert failures gracefully; 5. Using complex expressions in asserts; 6. Skipping assertions due to optimization; 7. Misunderstanding assert behavior in different environments.
Read More : https://factofit.com/7-common-mistakes-when-using-assert-for-debugging/
0 notes
Link
original source : https://agostini.tech/2017/10/01/assert-precondition-and-fatal-error-in-swift/
my review point is 9/10
Sometimes it’s better to crash then to have your app running in an inconsistent state. In this short article we’ll cover the options you have for crashing and what are the main differences between them. There’s only five, with some subtle differences. Let’s dive in.
Five Ways to Fail
You have five functions available to you if you want to stop the execution of your app (apart from exit() and abort(), but that’s not the topic of this article). And the five are:
assert()
assertionFailure()
precondition()
preconditionFailure()
fatalError()
We’ll go over each of them individually. But first…
Swift Optimisation Levels
To understand these assertions you need to understand optimisation levels. When you build your app the compiler will perform optimizations on your code in order to make it run faster. You can have different optimisation levels for different build configurations. These are the optimisation levels we’re interested in:
-Onone (default for debug builds)
-O (default for release builds)
-Ounchecked
You can set the optimisation level from your build settings. I won’t go into details about them here, I’ll just say, don’t use -Ounchecked If you have to use it, then you really know what you’re doing.
assert()
assert() is a function that takes in four parameters. Condition and the message are the ones you’ll be using. You probably won’t need file and line number (the last two parameters). With the assert() function you evaluate a condition, and if it evaluates to false, your app will stop executing. The condition will only be evaluated for -Onone builds. In other words, it will only work for debug builds. Let’s see a quick example of using assert:
func printAge(_ age: Int) { assert(age >= 0, "Age can't be a negative value")
print("Age is: ", age) }
printAge(-1)
// prints: assertion failed: Age can't be a negative value: file Assertions.playground, line 6
assertionFailure()
If you don’t have a condition to evaluate, or don’t need to evaluate one, you can use assertionFailure() function. It will take a string as an argument to print as the failure message. Like the assert, the function is called only for -Onone builds. Let’s modify our complex example to use assertionFailure
func printAge(_ age: Int) { guard age >= 0 else { assertionFailure("Age can't be a negative value") return } print("Age is: ", age) }
printAge(-1) // prints: fatal error: Age can't be a negative value: file Assertions.playground, line 9
precondition()
precondition() takes the same parameters as assert() and is pretty much doing the same thing. The only difference is that precondition works for -Onone and -O builds. In other words, for default debug and release configurations. You would use it the same way as you would use the assert:
func printAge(_ age: Int) { precondition(age >= 0, "Age can't be a negative value")
print("Age is: ", age) }
printAge(-1) // prints: precondition failed: Age can't be a negative value: file Assertions.playground, line 6
preconditionFailure()
You can see where this is going, right preconditionFailure() works the same as assertionFailure(). With the same difference as above, it works for -Onone and -O builds. Again, you would use it the same way you would use the assertionFailure:
func printAge(_ age: Int) { guard age >= 0 else { preconditionFailure("Age can't be a negative value") } print("Age is: ", age) }
printAge(-1) // prints: fatal error: Age can't be a negative value: file Assertions.playground, line 9
If you look a bit closely at the method signature for this function, you’ll see that it has a return type:
public func preconditionFailure(_ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line) -> Never
Return type ‘Never’ indicates that this function will never return. It will stop the execution of the app. That’s why Xcode won’t complain about the guard statement falling through because of the missing return statement.
fatalError()
fatalError(), like assertionFailure() and preconditionFailure(), takes a string as an argument that will be printed in the console before the app terminates. It works for all optimisation levels in all build configurations. You use it just like the other two:
func printAge(_ age: Int) { guard age >= 0 else { fatalError("Age can't be a negative value") } print("Age is: ", age) }
printAge(-1) // prints: fatal error: Age can't be a negative value: file Assertions.playground, line 9
And just like the preconditionFailure() it has a return type of ‘Never’.
That brings us to the end of the list.
Conclusion
A discussion at work sparked this article, and I simply wanted to do a bit more research on the subject. We were discussing whether to fail in production or not. Every project is different, and I’m sure you’ll be having heated debates with your colleagues on the same subject. These five methods are the options we have available to fail and it’s up to you to decide which one to use. In my personal opinion, I don’t really see the point of the precondition methods. fatalError makes perfect sense to me, even assert has a use when you’re in the middle of development, or you want to distribute debug builds to your beta customers. Using assertions for this purpose might make sense. Anyway, this is not an article on when to use assertions, I have a feeling it might be a religious topic for some
I hope you found this article useful, and as always…
Have a nice day
Dejan.
More resources
Apple: assert()
Apple: assertionFailure()
Apple: precondition()
Apple: preconditionFailure()
Apple: fatalError()
Marcin Krzyżanowski: Swift asserts – the missing manual
John Sundell: Picking the right way of failing in Swift
Andy Bargh: Swift Assertions
0 notes