Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-7486] assertionFailure should be deprecated or removed. #50029

Open
Lukasa opened this issue Apr 20, 2018 · 1 comment
Open

[SR-7486] assertionFailure should be deprecated or removed. #50029

Lukasa opened this issue Apr 20, 2018 · 1 comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella

Comments

@Lukasa
Copy link
Contributor

Lukasa commented Apr 20, 2018

Previous ID SR-7486
Radar None
Original Reporter @Lukasa
Type Bug
Status Reopened
Resolution
Environment

Swift 4.1

Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug
Assignee None
Priority Medium

md5: af2934e947ca5938fcdef4fe1e558ae1

Issue Description:

While investigating whether it was possible to convince Swift that a branch is unreachable, I discovered that assertionFailure is extremely surprising, and seems to have no sensible use-cases.

Consider the following simple function:

func test(int: Int?) -> Int {
    guard let int = int else {
        assertionFailure("Bang")
    }

    return int
}

When attempting to compile this function in debug mode, the following compiler error is emitted:

test.swift:4:5: error: 'guard' body must not fall through, consider using a 'return' or 'throw' to exit the scope

This is naturally fairly perplexing, but if the code is changed to add a return value, we could end up with the following program:

func test(int: Int?) -> Int {
    guard let int = int else {
        assertionFailure("Bang")
        return -1
    }

    return int
}

print(test(int: 5))
print(test(int: nil))

When compiled in debug mode and run, this produces the following output, as expected:

5
Fatal error: Bang: file test.swift, line 3
[1]    81717 illegal hardware instruction  ./test

When compiled with optimisations and run, this produces the following output:

5
-1

This strange strange behaviour boils down to the fact that `assertionFailure` is compiled away entirely in release mode. This means that it cannot be defined as returning `Never`, which is why surprise number 1 happens (namely, that you are forced to exit the `guard` scope in debug mode). And because it's compiled away in release mode, you run straight through it in release mode.

This function basically seems to be a worse-in-every-way version of `preconditionFailure`. It seems to serve no purpose. The distinction between assert and precondition is reasonable, as it allows coders to elide expensive checks that do not need to be run in release mode, but that does not apply here: assertionFailure and preconditionFailure are not expensive.

This confusion is widespread. For example, here is a blog post (Swift assertions: the missing manual) that mistakenly claims:

"Main difference is that assertionFailure() gives a hint to the optimizer that at this point, given context ("if" branch, or function context) ends, making it the @NoReturn effectively. In debug mode application will terminate, but in release behaviour is undefined."

This is not an accurate description of the behaviour of the function. I'd argue that it actually describes a more useful version of the function, where assertionFailure could be used to inform the compiler that a given branch should be unreachable. This was the effect I was trying to achieve when I bumped into this behaviour.

@belkadan
Copy link
Contributor

Under -Ounchecked it has the "optimizer hint" behavior, for when you really need that extra speed. But that's not really a recommended mode these days.

The purpose of assertionFailure is a pretty obscure one, but it does come up: you want to catch an error in a debug build, but in a production build it's more important to recover and keep going. Arguably you would still want to log in some way, though.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

2 participants