J. Cocoe J. Cocoe - 2 months ago 8
Swift Question

Why is Swift nil-coalescing returning an Optional?

First, I try mapping a

[String?]
, to get a
[String]
:

$ xcrun swift
Welcome to Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.30). Type :help for assistance.
1> import Foundation
2> let j: [String?] = ["a", nil]
j: [String?] = 2 values {
[0] = "a"
[1] = nil
}
3> j.map {$0 ?? ""}
$R0: [String] = 2 values {
[0] = "a"
[1] = ""
}


This makes perfect sense to me. I nil-coalesce a
String?
, and I get a
String
. But with
[AnyObject?]
, something strange occurs:

4> let k: [AnyObject?] = ["a", nil]
k: [AnyObject?] = 2 values {
[0] = "a"
[1] = nil
}
5> k.map {$0 ?? ""}
$R1: [AnyObject?] = 2 values {
[0] = "a"
[1] = (instance_type = 0x00007fff7bc2c140 @"")
}


I'm nil-coalescing optionals, but this time I get out an optional. Why?

The Swift Programming Language says
a ?? b
is shorthand for
a != nil ? a! : b
, but when I try that, I get out an array of non-optionals:

6> k.map {$0 != nil ? $0! : ""}
$R2: [AnyObject] = 2 values {
[0] = "a"
[1] = ""
}


Am I misunderstanding how
??
is supposed to work? What is going on here?

Answer

It has come to my attention that Apple considered this a bug in Swift 2.

In Swift 3, the 1st example above still works, while the 2nd and 3rd examples are invalid syntax (with or without Foundation bridging).

Replacing the AnyObject declaration with Any works: a ?? b then behaves identically to a != nil ? a! : b, as the documentation says.