Gauging community sentiment: `OptionalProtocol`

I think this would be very helpful when writing certain where clauses. A good example where this would help greatly is ResilientDecoding, where the following weird underscored public protocol and extension combo can be replaced by where WrappedValue: OptionalProtocol, WrappedValue.Some: Sequence {
https://github.com/airbnb/ResilientDecoding/blob/7a07262022d339aa04137db44e9e999f1d3f1ce5/Sources/ResilientDecoding/ResilientPropertyErrorInspection.swift#L121-L132

To be specific, the new protocol would look something like:

public protocol OptionalProtocol {
  associatedtype Some // Or whatever `Optional`'s associated type is
  static func some(_ value: Some) -> Self
}

I believe there were some proposals in the past that suggested an OptionalProtocol, but I think those focused too much on expanding the power of Optional unwrapping and thus quickly entered murky waters. In order to support my use case, all we would need is the protocol definition and the associated type. If folks feel positively about this, I can put a formal proposal together.

Note This issue already kind-of works in one direction via ExpressibleByNilLiteral, though that understandably doesn't give you access to the .some type.

1 Like

Would parameterized extensions address the problem?

If you don't need a protocol conformance or a property, you can sink the conditional where clause onto the individual methods that need the constraint:

extension Optional  {
  func foo<T>(...) where Wrapped == Resilient<[T]?>.ProjectedValue
}
6 Likes

For some cases, but if I want to define a function directly on Resilient<T?> with some constraints on T, I don't think there currently exists a way to do so (other than conforming Optional to a protocol I define, as in the example).

Update maybe I can specialize dynamicMember... I'll play around and report back

You can put the constraints on the function itself, rather than the extension:

extension Resilient {
  func foo<T>(...) where Wrapped == T?, T: SomeProtocol { ... }
}

I think the issue is that I'm defining properties in the extension, not functions. Though I was able to do a nasty workaround involving @dynamicMemberLookup. This workaround still requires a new public type (ArrayErrors) but doesn't require me conforming Optional to my own protocol type, which arguably makes it less nasty than what I have now.

UPDATE: This is the actual change: Use @dynamicMemberLookup instead of conforming Optional to a public protocol by GeorgeLyon · Pull Request #8 · airbnb/ResilientDecoding · GitHub though this is still nastier than it would look with either OptionalProtocol or some way of parameterizing properties.