What are assert and assertFailure?

Assert and assertFailure are functions that allow you to check for a condition at runtime and stop the execution of your program if the condition is not met. You can use them to verify that your code is working as expected and catch any bugs or logic errors early.

The syntax of assert is:

assert(condition, message)

where condition is a Boolean expression that evaluates to true or false, and message is an optional string that describes the error. If condition is true, the program continues normally. If condition is false, the program stops and prints the message to the console.

For example:

let age = 18
assert(age >= 18, "Age must be at least 18")
// The program continues because the condition is true
let age = 17
assert(age >= 18, "Age must be at least 18")
// The program stops and prints "Assertion failed: Age must be at least 18"

The syntax of assertFailure is:

assertFailure(message)

where message is an optional string that describes the error. This function always stops the execution of the program and prints the message to the console. You can use it when you encounter a situation that should never happen in your code.

For example:

let name = "Alice"
switch name {
case "Alice":
    print("Hello, Alice")
case "Bob":
    print("Hello, Bob")
default:
    // This case should never happen
    assertFailure("Unknown name")
}
// The program prints "Hello, Alice" and continues normally
let name = "Charlie"
switch name {
case "Alice":
    print("Hello, Alice")
case "Bob":
    print("Hello, Bob")
default:
    // This case should never happen
    assertFailure("Unknown name")
}
// The program stops and prints "Assertion failed: Unknown name"

What are precondition and preconditionFailure?

Precondition and preconditionFailure are similar to assert and assertFailure, but they have some differences. Precondition and preconditionFailure are functions that allow you to check for a condition at compile time and stop the execution of your program if the condition is not met. You can use them to enforce the requirements of your code and ensure that your program is in a valid state.

The syntax of precondition is:

precondition(condition, message)

where condition is a Boolean expression that evaluates to true or false, and message is an optional string that describes the error. If condition is true, the program continues normally. If condition is false, the program stops and prints the message to the console.

For example:

func divide(_ x: Int, by y: Int) -> Int {
    // The divisor must not be zero
    precondition(y != 0, "Division by zero")
    return x / y
}

let result = divide(10, by: 2)
// The program continues because the condition is true
func divide(_ x: Int, by y: Int) -> Int {
    // The divisor must not be zero
    precondition(y != 0, "Division by zero")
    return x / y
}

let result = divide(10, by: 0)
// The program stops and prints "Precondition failed: Division by zero"

The syntax of preconditionFailure is:

preconditionFailure(message)

where message is an optional string that describes the error. This function always stops the execution of the program and prints the message to the console. You can use it when you encounter a situation that violates the assumptions of your code.

For example:

func greet(_ name: String) {
    guard !name.isEmpty else {
        // The name must not be empty
        preconditionFailure("Empty name")
    }
    print("Hello, \(name)")
}

greet("Alice")
// The program prints "Hello, Alice" and continues normally
func greet(_ name: String) {
    guard !name.isEmpty else {
        // The name must not be empty
        preconditionFailure("Empty name")
    }
    print("Hello, \(name)")
}

greet("")
// The program stops and prints "Precondition failed: Empty name"

What is fatalError?

FatalError is a function that allows you to stop the execution of your program and print a message to the console. You can use it when you encounter a situation that is impossible to recover from or handle in your code.

The syntax of fatalError is:

fatalError(message)

where message is an optional string that describes the error. This function always stops the execution of the program and prints the message to the console.

For example:

enum Animal {
    case dog, cat, bird
}

func makeSound(_ animal: Animal) {
    switch animal {
    case .dog:
        print("Woof")
    case .cat:
        print("Meow")
    case .bird:
        print("Tweet")
    default:
        // This case should never happen
        fatalError("Unknown animal")
    }
}

makeSound(.dog)
// The program prints "Woof" and continues normally
enum Animal {
    case dog, cat, bird
}

func makeSound(_ animal: Animal) {
    switch animal {
    case .dog:
        print("Woof")
    case .cat:
        print("Meow")
    case .bird:
        print("Tweet")
    default:
        // This case should never happen
        fatalError("Unknown animal")
    }
}

makeSound(.fish)
// The program stops and prints "Fatal error: Unknown animal"

Summary

FunctionWhen to useWhen it works
assertTo check for a condition at runtime and stop the execution if the condition is not metOnly in debug mode
assertFailureTo indicates that an internal sanity check failedOnly in debug mode
preconditionTo check for a condition at compile time and stop the execution if the condition is not metIn both debug and release mode
preconditionFailureTo indicate that a situation that violates the assumptions of the code has occurred at compile timeIn both debug and release mode
fatalErrorTo stop the execution of the program and print a message to the console when there is no way to recover or handle the errorIn both debug and release mode

Conclusion

In this blog post, we have learned how to use these functions to improve the quality and reliability of our code and avoid unexpected crashes or bugs. Thanks for reading!