What is the Never return type?

Never return type was introduced in Swift 3 to substitute @noreturn key.

See justification in this proposal:
SE-0102 Remove @noreturn attribute and introduce an empty Never type

As official documentation explains:

The return type of functions that do not return normally; a type with
no values.

Use Never as the return type when declaring a closure,
function, or method that unconditionally throws an error, traps, or
otherwise does not terminate.

Source: https://developer.apple.com/documentation/swift/never

Basic illustration:

// The following function is our custom function we would use
// to manually and purposefully trigger crash. In the logs,
// we can specify what exactly went wrong: e.g. couldn't cast something, 
// couldn't call something or some value doesn't exist:
func crashApp() -> Never {
    fatalError("Something very, very bad happened! Crash the app!")
}

Usage specifics and advantages over @noreturn, as referenced by Erica Sadun:

  • Never allows a function or method to throw: e.g. () throws -> Never. Throwing allows a secondary path for error remediation, even in functions that were not expected to return.
  • As a first class type, Never works with generics in a way that the @noreturn attribute could not.
  • Never proactively prevents a function from claiming both a return type and no-return at the same time. This was a potential issue under the old system.

First note (regarding secondary error remediation) is probably particularly important. Never function can have complex logic and throw – not necessarily crash.

Let’s see some interesting use cases and comparison between Never and Void

Never

Example 1

func noReturn() -> Never {
    fatalError() // fatalError also returns Never, so no need to `return`
}

func pickPositiveNumber(below limit: Int) -> Int {
    guard limit >= 1 else {
        noReturn()
        // No need to exit guarded scope after noReturn
    }
    return rand(limit)
}

Example 2

func foo() {
    abort()
    print("Should not reach here") // Warning for this line
}

Example 3

func bar() -> Int {
    if true {
        abort() // No warning and no compiler error, because abort() terminates it.
    } else {
        return 1
    }
}

abort() is defined as:

public func abort() -> Never

Void

These examples would not have been possible with it returning Void:

public func abortVoid() -> Void {
    fatalError()
}

func bar() -> Int {
    if true {
        abortVoid() // ERROR: Missing return in a function expected to return 'Int'
    } else {
        return 1
    }
}

And to pack it up with abort() returning Never:

func bar() -> Int {
    if true {
        abort() // No ERROR, but compiler sees it returns Never and warns:
        return 2 // Will never be executed
    } else {
        return 1
    }
}

We use Void to tell compiler there is no return value. Application keeps running.

We use Never to tell compiler there is no return to caller site. Application runloop is terminated.

Leave a Comment

error code: 521