Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 988
J. Cocoe Avatar asked Aug 05 '16 21:08

J. Cocoe


People also ask

What is nil coalescing in Swift?

Discussion. A nil-coalescing operation unwraps the left-hand side if it has a value, or it returns the right-hand side as a default. The result of this operation will have the non-optional type of the left-hand side's Wrapped type.

What is optional chaining nil coalescing operator?

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil . If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil , the property, method, or subscript call returns nil .

What is nil in Swiftui?

In Swift, nil means the absence of a value. Sending a message to nil results in a fatal error. An optional encapsulates this concept. An optional either has a value or it doesn't.

What is if let Swift?

The “if let” allows us to unwrap optional values safely only when there is a value, and if not, the code block will not run. Simply put, its focus is on the “true” condition when a value exists.


1 Answers

The detailed behaviour is not well-documented, so, would change in the future Swifts.

But you should know coalescing operator has two overloads:

@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T) rethrows -> T

@warn_unused_result
public func ??<T>(optional: T?, @autoclosure defaultValue: () throws -> T?) rethrows -> T?

In your case, Swift has chosen the latter for your code.

You can test with a simplified codes like:

let x: AnyObject? = "a"
x ?? ""

The inferred type (in Swift 2.2.1) becomes AnyObject?. But this code is also valid.

let y: AnyObject = x ?? ""

String literals like "" can be treated as variety of types. All of these are valid in Swift.

"" as String
"" as String?
"" as NSString
"" as NSString?
"" as AnyObject
"" as AnyObject?

So, with some unspecified reason Swift has chosen AnyObject?. And, in case type inference can be ambiguous, you should use explicit type annotation, as suggested in appzYourLife's comment.

like image 143
OOPer Avatar answered Oct 05 '22 06:10

OOPer