try?, precedence and double optionals


(Tim Vermeulen) #1

Given the function

func mightReturnInt() throws -> Any {
    return 3
}

combining `try?` and `as?` has a somewhat unexpected result:

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

You’d need to add parentheses to end up with a non-optional:

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

Apparently, `try?`’s precedence is lower than `as?`’s precedence. Should this be changed?

On a similar note:

func mightReturnInt() throws -> Int? {
    return 3
}

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

Here, `try?` acts as a map, not as a flatMap, resulting in a double optional (and in a single optional after unwrapping it). None of the possible workarounds are particularly pretty:

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

or:

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

Once again, is this behaviour expected and desired, or should it be changed while it still can?


(Xiaodi Wu) #2

This question was asked a few months back on this list--I can't recall
exactly when, but there were some useful comments there that would be worth
revisiting.

···

On Fri, Dec 2, 2016 at 16:16 Tim Vermeulen via swift-evolution < swift-evolution@swift.org> wrote:

Given the function

func mightReturnInt() throws -> Any {
    return 3
}

combining `try?` and `as?` has a somewhat unexpected result:

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

You’d need to add parentheses to end up with a non-optional:

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

Apparently, `try?`’s precedence is lower than `as?`’s precedence. Should
this be changed?

On a similar note:

func mightReturnInt() throws -> Int? {
    return 3
}

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

Here, `try?` acts as a map, not as a flatMap, resulting in a double
optional (and in a single optional after unwrapping it). None of the
possible workarounds are particularly pretty:

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

or:

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

Once again, is this behaviour expected and desired, or should it be
changed while it still can?
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution