10

I read the code block enclosed in curly braces after the keyword else in the context of a guard-else flow, must call a function marked with the noreturn attribute or transfer control using return, break, continue or throw.

The last part is quite clear, while I don't understand well the first.

First of all, any function returns something (an empty tuple at least) even if you don't declare any return type. Secondly, when can we use a noreturn function? Are the docs suggesting some core, built-in methods are marked with noreturn?

The else clause of a guard statement is required, and must either call a function marked with the noreturn attribute or transfer program control outside the guard statement’s enclosing scope using one of the following statements:

return

break

continue

throw

Here is the source.

Emre Aktürk
  • 3,306
  • 2
  • 18
  • 30
  • 1
    Take a look at: http://stackoverflow.com/questions/27829132/convincing-swift-that-a-function-will-never-return-due-to-a-thrown-exception – Duyen-Hoa Jun 29 '16 at 12:01

3 Answers3

16

First of all, any function returns something (an empty tuple at least) even if you don't declare any return type.

(@noreturn is obsolete; see Swift 3 Update below.) No, there are functions which terminate the process immediately and do not return to the caller. These are marked in Swift with @noreturn, such as

@noreturn public func fatalError(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func preconditionFailure(@autoclosure message: () -> String = default, file: StaticString = #file, line: UInt = #line)
@noreturn public func abort()
@noreturn public func exit(_: Int32)

and there may be more.

(Remark: Similar annotations exist in other programming languages or compilers, such as [[noreturn]] in C++11, __attribute__((noreturn)) as a GCC extension, or _Noreturn for the Clang compiler.)

You can mark your own function with @noreturn if it also terminates the process unconditionally, e.g. by calling one of the built-in functions, such as

@noreturn func myFatalError() {
    // Do something else and then ...
    fatalError("Something went wrong!")
}

Now you can use your function in the else clause of a guard statement:

guard let n = Int("1234") else { myFatalError() }

@noreturn functions can also be used to mark cases that "should not occur" and indicate a programming error. A simple example (an extract from Missing return UITableViewCell):

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: MyTableViewCell

    switch (indexPath.row) {
    case 0:
        cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! MyTableViewCell
        cell.backgroundColor = UIColor.greenColor()
    case 1:
        cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! MyTableViewCell
        cell.backgroundColor = UIColor.redColor()
    default:
        myFatalError()
    }
    // Setup other cell properties ...
    return cell
}

Without myFatalError() marked as @noreturn, the compiler would complain about a missing return in the default case.


Update: In Swift 3 (Xcode 8 beta 6) the @noreturn attribute has been replaced by a Never return type, so the above example would now be written as

func myFatalError() -> Never  {
    // Do something else and then ...
    fatalError("Something went wrong!")
}
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    There is also `UIApplicationMain` which never returns (although it is not marked so probably because of backward compatibility). It was a problem in Obj-C that calls like `[NSException raise]` were not recognized by the compiler and there still had to be a `return` after them. – Sulthan Jun 29 '16 at 12:02
  • 1
    @Sulthan: Probably. And you wouldn't call UIApplicationMain() in a guard statement :) – Martin R Jun 29 '16 at 12:07
  • @MartinR: I know I can use it for a custom function, I tried before posting :-) My question was: has any sense for a developer to have a function marked that way? I was looking for a use case :-) –  Jun 29 '16 at 12:19
  • 1
    @IanBell: The use-case is that you can use your custom function in the else-clause of a guard statement, and the compiler *knows* that it will never return. I have added another example. Without the `@noreturn` attribute, both examples would not compile. – If you don't have function which terminate the process unconditionally then you don't need it! – Martin R Jun 29 '16 at 12:34
  • @MartinR: it's ok, I was simply looking for something more concrete, but that's ok, thanks :-) –  Jun 29 '16 at 12:48
  • 1
    @IanBell There are lots of reasons to use it, you could be working on a multi threaded application, say one that does a network download, and during this download process, you have something that fails the guard. If the function returns it will fire a completion event, which you do not want, but you also need to keep the thread alive momentarily. Now imagine several places where this code exists and you do not want to write duplicate else conditions, you would use this function on all these else conditions, this then allows for your thread to die without firing a completion event. – Knight0fDragon Aug 18 '16 at 13:48
1

simple playground to see how it works ...

//: Playground - noun: a place where people can play

import Foundation
@noreturn func foo() {
    print("foo")
    exit(1)
}

var i: Int?

guard let i = i else {
    foo()
}

print("after foo") // this line will never executed

//prints foo and finish
user3441734
  • 16,722
  • 2
  • 40
  • 59
  • 1
    I kwow how it works, thanks, but what I was looking for was a concrete, real example in which this attribute can be very useful :-) –  Jun 29 '16 at 12:49
  • 1
    @IanBell so, you see the example ... :-). try to imagine that foo() does some cleaning before exit, or even transfer some data to the server or whatever you want. The task could be very complex, it is up to you. – user3441734 Jun 29 '16 at 12:54
  • same here... how can @noreturn (now "Never") be useful... really, in a real example... – zumzum Sep 20 '16 at 19:56
  • @IanBell as another example that brought me here was that: normally in a *guard* statement you have a `return` at the end of the failure scenario...but this time in my failure I wrote a `preconditionFailure` and the compiler was giving me a *warning:* "will never be executed" on the return line...because the preconditionFailure literally marks the end of my code execution – mfaani Jun 01 '17 at 19:58
0

For instance, consider an assync operation that return either a value or error in result type. We usually write this as follows.

enum Result<Value, Error> {
    case success(Value)
    case failure(Error)
}

func fetch(_ request: URLRequest,
          completion: (Result<(URLResponse, Data), Error>) -> Void) {
    // ...
}

Now, if you know a function that always return value, never an error, then we could write :

func alwaysSucceeds(_ completion: (Result<String, Never>) -> Void) {
    completion(.success("yes!"))
}

When compiler see Never, it won't force you to write all the switch cases to be exhaustive, so you can skip .failure as follows.

alwaysSucceeds { (result) in
    switch result {
    case .success(let string):
        print(string)
    }
}

Ref : https://nshipster.com/never/

Abhijith
  • 3,094
  • 1
  • 33
  • 36