Swift Optional Type Syntax

921 Views Asked by At

According to Apple's Swift guide, when you have the following Array and the following function to search through an Array:

let namesArray = ["John", "Lisa", "Bill", "Jennifer"]

// Note this function is set-up to return an OPTIONAL Int:
func findName (personName:String, arrayToSearchIn:String[]) -> Int? {
    for (indexOfName, nameValue) in enumerate(arrayToSearchIn) {
       if nameValue == personName {
          return indexOfName
       }
    }
    return nil
}

...so you can capture the Optional Int returned by this function - and then check to see if its nil or not - in the following manner:

let nameIndex: Int? = findName("Lisa", arrayToSearchIn: namesArray)
if nameIndex {
    println("found \(namesArray[nameIndex!])")
}
else {
    println("NOT found")
}

This is all good - but their next example, in which they streamline the code by collapsing the 2 statements into one - confuses me because they suddenly drop the Optional "?" and "!" from their syntax:

if let nameIndex = findName("Lisa", arrayToSearchIn: namesArray) {
   println("found \(namesArray[nameIndex])")
}

And this works perfectly well.

So why is it that in the first example nameIndex was declared with a "?" - like so:

nameIndex:Int?

and the forced-unwrapping occurs using a "!"

[nameIndex!]

but in the second example neither "?" or "!" one is used in the syntax?

2

There are 2 best solutions below

2
On

? is the operator to explicitly declare an optional type. ! is the operator to force-unwrap an optional. The syntax in the example is a special Swift shorthand for checking and unwrapping in one concise line. It says, “assign nameIndex to the result of findName(...), and if it is not nil, run the following code: ...”

5
On

The handling of the declaration in an if let is special; one should treat it as its own language construct (not as a simple combination of if and let). In

if let nameIndex = findName("Lisa", arrayToSearchIn: namesArray) {
   println("found \(namesArray[nameIndex]")
}

the type of nameIndex does not need to be expressed because it can be inferred as the return type of findName() which is Int?. In the body of the if let ... the value of nameIndex is not bound to an optional and thus unwrapping is not needed - the value will be an Int.

Here is an example of how the if let binding is treated. Notice that an explicit declaration of the type is essentially ignored:

> func test () -> Int? { return 111 }
> if let x : Int? = test () { return x }
$R6: Int? = 111
> if let x : Int = test () { return x }
$R7: Int = 111
> if let x = test () { return x }
$R8: Int = 111

but if you try to be so 'flexible' outside of an if let, you draw an error from the compiler:

> let y : Int = test ()
<REPL>:33:15: error: value of optional type 'Int?' not unwrapped; 
   did you mean to use '!' or '?'?