Search code examples
swiftsyntaxclosuresimplicit-typing

Adding inline explicit type annotations to a closure with a return value but no input parameters in Swift?


Normally a function doesn't need explicit types since it can infer the type from the context:

let f = { input in
  1 + input
}
f(2)

Oftentimes you need to provide an explicit type annotation to force it to use a specific type, or in case the compiler cannot infer the type. This is straightforward when you have an input parameter:

let f = { (input: Double) -> Double in
  1 + input
}
f(2)

However, if you don't have an input parameter, I'm not sure what the syntax is supposed to look like:

let f = { -> Double in
  1 + 1
}
f()

error: Expected expression

I tried all of these variations to no avail:

  • let f = { -> Double in: "error: Expected expression"
  • let f = { _ -> Double in: "error: unable to infer type of a closure parameter '_' in the current context", this also changes it to take in an argument, which is not what I want.
  • let f = { Void -> Double in: "error: unable to infer type of a closure parameter 'Void' in the current context"
  • let f = { Never -> Double in: "error: unable to infer type of a closure parameter 'Never' in the current context"

I was able to get it working by adding an as clause to the end, but this seems verbose and like an oversight if there's no way to define just an explicit return type for a closure using this syntax.

let f = {
  1 + 1
} as () -> Double
f()

How do I define an explicit return type for a closure (using inline syntax instead of as), if it has no input parameters?


Note: I'm happy to close this as a duplicate if another question already exists. (I tried searching for duplicates using the terms explicit type annotation closure return only and couldn't find anything relevant.)


Solution

  • The empty tuple () indicates an empty argument list:

    let f = { () -> Double in
      1 + 1
    }
    
    print(f()) // 2.0
    

    () can be both a type (identical to Void) and an instance of that type:

    let a: Void = ()
    let b: () = ()
    print(type(of: a) == type(of: b)) // true