Generic Constraints Swift 4.2 Behavior not consistent

Hello!

I am encountering some behavior using generics with protocols & adding generic constraints to conformances of the protocol.

**note I am running Xcode 10 & Swift 4.2

tldr;

//Implements a function in ObserverType protocol with a generic constraint
func did<T>(start operation: T) where T : Async {
        print(#function + " T : Async")
    }

    func did<T>(start operation: T) {
        print(#function)
    }

the following code:

var observers : [ObserverType] = []
operation.observers.forEach { $0.did(start: operation) }

results in the following function being called

func did<T>(start operation: T) {
        print(#function)
    }

Without the generic constraints? I would think that if I define a function with generic constraints that it would be called?

The interesting thing is if I call:

obs.did(start: operation)

directly, the generic constraints function will be called.

I tried to condense the context as much as possible, hopefully this illustrates the issue. Appreciate any insights / solutions/ workarounds.

I also have a gist with the full code (copy and paste into a Playground):

Cheers

In $0.did(start: operation), you're calling did on an object of type ObserverType that only has one did requirement, which is appropriately called. If you want an overload resolution to take place, you should call did on AnyObserver or AsyncObserver, like you do in obs.did(start: operation).

Do you have a suggestion for the use case of where the array could contain different types that conform to ObserverType?

If you want the compiler to choose the best-matching overload among the did methods upon a call, all those methods have to be members of the dynamic callee type (ObserverType in your case). So you would have to make them part of ObserverType.

In case this brings clarity, your case doesn't work for the same reason you can't do this:

protocol Foo {
  func foo()
}
class Class: Foo {
  func foo() {}
  func doo() {}
}

let bar: Foo = Class()
bar.doo()
1 Like