Unexpected precedence issues with try? and as?

Tim Vermeulen recently wrote on the Swift Evolution list that try? precedence can be unexpected:

if let int = try? mightReturnInt() as? Int {
 print(int) // => Optional(3)
}

Specifically, he discovered that try?’s precedence is lower than as?’s precedence, so you may have to add parentheses to get the right result.

if let int = (try? mightReturnInt()) as? Int {
    print(int) // => 3
}

He also found a similar issue with using try? on a throwing-optional-returning scenario:

if let int = try? mightReturnInt() {
    print(int) // => Optional(3)
}

if let int = (try? mightReturnInt()) ?? nil {
    print(int) // => 3
}

There’s some magic baked into if let item = item as? T that automatically lifts optionals, which doesn’t yet seem to extend to try?. If you’re running into these situations, consider adding parentheses and nil-coalescing as demonstrated in these examples.

In case you think a throwing-optional scenario is too “out there”, think of a file system request that would throw on an unreadable directory and return nil if a specific file does not exist. Although obscure, it is not unthinkable to combine the two approaches.

2 Comments

  • I noticed a slight typo referencing the wrong variable. It looks like the final print command should be using the `temp` variable, not the `int` variable.

    Thanks for posting this, it’s definitely something to be aware of!

    • Thanks, please check my fix (I changed it to “int” from “temp”)