Why doesn't "try? funcReturningOptionalInt()" give "Int?"

Related thread: try? with a function that returns an optional.

Consider the following example:

func foo() throws -> Int? { 1 }

let x = try? foo()
type(of: x)  // returns 'Int?' instead of 'Int??'

Why doesn't try? always give an optional of the return type?

This: https://github.com/apple/swift-evolution/blob/main/proposals/0230-flatten-optional-try.md

4 Likes

Thank you! I'm honestly a bit sad since this implicit flattening removes information. Without it you would be able to directly check if a function has thrown since Optional(nil) is different from nil. I hope it has been considered during the review phase of SE-0230.

I believe it was, so you might look into the discussion, which is linked in the proposal header.

But my take is that if I ever write try? instead of the standard try-catch ceremony, then I already don't care for the source of optionality. It is anyway more likely that if you ever want to have the knowledge that the optionality comes from an error and not the underlying return type, you'd want to investiagate it within a catch block like any other error, and not by counting the levels of nested optionals, which might be even more unreliable and confusing :upside_down_face:

8 Likes

I face the similar problem. Thanks for update and quick reply.

official website

Seems to me like a better solution than try?-flattening everything would have been to add a static unwrap method for opting in.

Because this is also an Int?:

let int = try? .unwrap(foo)

As it is, if we get a proper throwing unwrapping method, this will become easy on you.

do {
  // The necessity for explicit typing here is going away, I think.
  let int = try Int?.unwrap(foo)
} catch let error as Optional<Int>.UnwrapError {
  
} catch {

}
public extension Optional {
  final class UnwrapError: AnyOptional.UnwrapError { }

  static func unwrap(
    _ optional: () throws -> Self
  ) throws -> Wrapped {
    try optional().unwrap()
  }

  /// - Note: Useful for emulating `break`, with `map`, `forEach`, etc.
  /// - Throws: if `nil`.
  func unwrap(
    orThrow error: @autoclosure () -> Error = UnwrapError()
  ) throws -> Wrapped {
    if let wrapped = self {
      return wrapped
    } else {
      throw error()
    }
  }
}

public enum AnyOptional {
  public class UnwrapError: Error {
    public init() { }
  }
}
Terms of Service

Privacy Policy

Cookie Policy