frankleonrose frankleonrose - 4 years ago 169
Swift Question

Swift Generic func gen<T>(arg: T) where T : Optional<U>, U : Equatable

How do I express a Swift generic function which constraints that

be an

I've tried things like the following, with the resulting errors.

func gen<T>(arg: T) where T : Optional<Equatable>

  • Type 'T' constrained to non-protocol type 'Optional'

func gen<T>(arg: T) where T : OptionalProtocol<Equatable>

  • Cannot specialize non-generic type 'OptionalProtocol'

func gen<T, U>(arg: T) where T : Optional<U>, U : Equatable

  • Type 'T' constrained to non-protocol type 'Optional'

  • Generic parameter 'U' is not used in function signature



I was doing something like

if let a = arg, let b = argb
return a==b

It turns out that my error wasn't in the templating at all, it was just that the object I was working with wasn't, in fact, Equatable. I guess I assumed Swift would generate == for a struct with elements that are all themselves =='able, but it does not. Next time I'll know what the error
Expression type 'Bool' is ambiguous without more context
is suggesting.

Answer Source

This should work:

func gen<T>(arg: T?) where T : Equatable { /*...*/ }

Which is equivalent to this:

func gen<T>(arg: Optional<T>) where T : Equatable { /*...*/ }


  1. Generics are for the variable part of your type requirements. That you require Optional is constant; it's the optional-what part that's variable. So put the optionality in the actual func declaration, and leave the optional-what for generics.

  2. The colon in type parameters expresses a subtype relationship. A type T can't be a subtype of Optional<Something> because Optional is an enum — only classes and protocols can have subtypes (subclasses and conforming types respectively). Likewise, generics aren't covariant, so Optional<Foo> where Foo adopts Equatable isn't a subtype of Optional<T: Equatable>.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download