Should `Optional` conditionally conform to the `ExpressibleBy_` family of protocols?

I believe that Optional does not conform to these protocols because we typically lean on optional promotion for seamless coercion at the call site. However, there are times that this does not work. Take for example this simple Wrapper type that conditionally conforms to ExpressibleByIntegerLiteral:

struct Wrapper<A> {
  let value: A
}

extension Wrapper: ExpressibleByIntegerLiteral where A: ExpressibleByIntegerLiteral {
  typealias IntegerLiteralType = A.IntegerLiteralType
  init(integerLiteral value: A.IntegerLiteralType) {
    self.init(value: A.init(integerLiteral: value))
  }
}

I then want to create the following type alias:

typealias OptionalWrapper<A> = Wrapper<A?>

Because Optional is not ExpressibleByIntegerLiteral, I cannot simply do:

let value: OptionalWrapper<OptionalWrapper<Int>> = 2

This is because the actual type of value is Wrapper<Wrapper<Int?>?>. To get it to work I need to supply:

extension Optional: ExpressibleByIntegerLiteral where Wrapped: ExpressibleByIntegerLiteral {
  public typealias IntegerLiteralType = Wrapped.IntegerLiteralType
  public init(integerLiteral value: Wrapped.IntegerLiteralType) {
    self = .some(.init(integerLiteral: value))
  }
} 

And then it works as expected. But, I’m not likely to include this in my code because of potential conflicts with other libraries.

So, I’m wondering if Optional should conform to the expressible family of protocols?


NB: The code provided is just to demonstrate the problem, but for a real world example you can see this gist: https://gist.github.com/mbrandonw/9b6416091466d9cad7a4035809734ea7

6 Likes

This sounds like it fits Swift very well, as optionals are kind of expected to be initializable from an instance of the type they are wrapping. Literals shouldn’t be in the way of this.
I’d love to see a proposal for this.