Skip to content

Instantly share code, notes, and snippets.

@stigi
Created May 24, 2016 19:29
Show Gist options
  • Select an option

  • Save stigi/0dec0f072119c9c8e150e8e4a954929e to your computer and use it in GitHub Desktop.

Select an option

Save stigi/0dec0f072119c9c8e150e8e4a954929e to your computer and use it in GitHub Desktop.
import Foundation
protocol ProtocolType {
func test() -> ()
}
struct StructOne: ProtocolType {
func test() -> () {}
}
struct StructTwo: ProtocolType {
func test() -> () {}
}
struct StructThree: ProtocolType {
func test() -> () {}
}
func doSomethingGeneric<T where T:ProtocolType>(with: T) -> () {
print("protocol")
}
func doSomethingGeneric(with: StructOne) -> () {
print("struct one")
}
func doSomethingGeneric(with: StructTwo) -> () {
print("struct two")
}
doSomethingGeneric(StructOne())
doSomethingGeneric(StructTwo())
doSomethingGeneric(StructThree())
let array:[ProtocolType] = [StructOne(), StructTwo(), StructThree()]
array.forEach(doSomethingGeneric) // <- why does this not work?
@stigi
Copy link
Copy Markdown
Author

stigi commented May 24, 2016

There are two issues:

  • The way the code is written the compiler errors: "Ambiguous reference to member 'doSomethingGeneric'"
  • If I remove all but the first definition of doSomethingGeneric the compiler errors: "Cannot convert value of type '(_) -> ()' to expected argument type '(ProtocolType) -> Void'"

When I print("\(array.dynamicType.Generator.Element.self)") it outputs ProtocolType so I'd assume the function signature for the forEach argument to be (ProtocolType) -> ()

@stigi
Copy link
Copy Markdown
Author

stigi commented May 25, 2016

Declaring the generic function the following way doesn't help:

func doSomethingGeneric<T:ProtocolType where T:ProtocolType>(with: T) -> () 

@stigi
Copy link
Copy Markdown
Author

stigi commented May 25, 2016

Using array.forEach { doSomethingGeneric($0) } gives me the following error: "Cannot invoke 'doSomethingGeneric' with an argument list of type '((ProtocolType))'"

@ole
Copy link
Copy Markdown

ole commented May 25, 2016

It works if you declare the function like this:

func doSomethingGeneric<T where T:ProtocolType>(with: T) -> () {
    print("protocol")
}

(You don't have to remove the other two definitions of the function. I don't know why you got the "ambiguous reference" error before. Probably because the compiler could not yet determine the type of the argument inside the forEach closure before it found a suitable declaration of doSomethingGeneric so it treats all matching functions as candidates.)

The reason is (I think) that ProtocolType is a different type than T where T: ProtocolType. The latter describes a single concrete type T that adopts ProtocolType. Your array is a heterogeneous collection of different types that all conform to ProtocolType. That is not the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment