Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call the more specific method of overloading

Here is an example playground:

protocol P {
    associatedtype T
    func getValue() -> T
}

class Foo: P {
    func getValue() -> String {
        return "hello"
    }
}

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test(_ o: Any) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
bar.test(foo)

This outputs: Any.

If I remove the Any version of test, the generic method is called. Class Foo conforms to protocol P, why does Swift not pick the generic method since it is more specific? Is there a way to call the generic one?

like image 944
Arnol Avatar asked Jan 08 '17 10:01

Arnol


1 Answers

From what I understand, the compiler will always favour an explicitly typed parameter over a generic one when performing overload resolution. Thus in the resolution between test<T : P>(_ o: T) and test(_ o: Any) – the latter will be preferred as it has an explicit (albeit abstract) parameter type, whereas the first is merely a placeholder.

Therefore if you make the second overload generic as well, the compiler will now favour the first overload, as they both don't have explicitly typed parameters, but the first overload is more tightly constrained:

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test<T>(_ o: T) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
bar.test(foo) // Generic hello

Keeping the overloads as-is, type-casting in order to disambiguate also appears to be a viable solution:

class Bar {
    func test<T: P>(_ o: T) {
        print("Generic", o.getValue())
    }

    func test(_ o: Any) {
        print("Any")
    }
}

let foo = Foo()
let bar = Bar()
(bar.test as (Foo) -> Void)(foo) // Generic hello

Although I would strongly recommend the first approach, as it allows you to reason better about what overload will be chosen (generics should also be preferred in general over protocol-typed parameters wherever possible, due to the performance benefits of specialisation).

like image 165
Hamish Avatar answered Sep 25 '22 22:09

Hamish