4

I want to use nil-coalescing operator to set a default value in both the following cases:

  1. function throws an error
  2. function returns nil

Please take a look at the code snippet below. I have the following questions:

  1. Why is item1 nil?
  2. What is the difference between the initialization of item1 vs item2
enum VendingMachineError: Error {
    case invalidCode
}

class VendingMachine {
    func itemCode(code: Int) throws -> String? {
        guard code > 0 else {
            throw VendingMachineError.invalidCode
        }
        if code == 1 {
            return nil
        } else {
            return "Item #" + String(code)
        }
    }
}

let machine = VendingMachine()

// Question: Why is this nil?
let item1 = try? machine.itemCode(code: 0) ?? "Unknown"
print(item1)
// nil

// What is the difference between the initialization of item1 vs item2
let item2 = (try? machine.itemCode(code: 0)) ?? "Unknown"
print(item2)
// Unknown

Raunak
  • 3,314
  • 1
  • 22
  • 28
  • 1
    Btw, the behavior of `try?` with an optional expression changed in Swift 5, compare https://stackoverflow.com/q/39691178/1187415. Previously it evaluated to a “double optional” value. – Martin R Aug 20 '19 at 07:39

1 Answers1

8

Essentially, this has to do with the grammar of the try operator. When used with a binary expression without brackets, try applies to the whole binary expression, so this:

try? machine.itemCode(code: 0) ?? "Unknown"

is the same as:

try? (machine.itemCode(code: 0) ?? "Unknown")

Since itemCode throws an error, the latter part of the expression ?? "Unknown is ignored, and the try? expression evaluates to nil.

On the other hand, the second expression is like this:

(try? machine.itemCode(code: 0)) ?? "Unknown"

The try? expression is evaluated first (to nil), then the ?? is applied, evaluating the whole expression to "Unknown".

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 1
    Nitpicking: I *think* that `try` is not an operator but a keyword. The “precedence” is induced by the grammar, not by operator precedence. (Compare "expression", "primary-expression" and "parenthesized-expression" in https://docs.swift.org/swift-book/ReferenceManual/Expressions.html.) – Martin R Aug 20 '19 at 07:15
  • 1
    @MartinR [The Language Reference calls it an operator though](https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#grammar_try-operator) – Sweeper Aug 20 '19 at 07:17
  • Yes, I saw that. But, unless I am mistaken, there is no precedence (group) defined for that “operator.” – Martin R Aug 20 '19 at 07:18
  • 1
    @MartinR Ok, I see what you mean. – Sweeper Aug 20 '19 at 07:26