Stephen H. Gerstacker
Stephen H. Gerstacker

Reputation: 763

Precedence of Function Overloading Parameters in Swift

I have the following contrived example:

protocol Fooable { }

extension Int: Fooable { }
extension Double: Fooable { }
extension Bool: Fooable { }

func go(value: Any, type: Fooable.Type) -> String {
    return "Fooable"
}

func go(value: Any, type: Int.Type) -> String {
    return "Int"
}

func go(value: Any, type: Double.Type) -> String {
    return "Double"
}

let value1 = 1
go(value: value1, type: type(of: value1)) // Returns "Int"

let value2 = 2.0
go(value: value2, type: type(of: value2)) // Returns "Double"

let value3 = true
go(value: value3, type: type(of: value3)) // Returns "Fooable"

This is the behavior I ultimately want, but what sets this precedence? The more generic, first function can be placed anywhere in the code, giving the same results, so there must be some sort of precedence rules.

Is this outlined anywhere?

Upvotes: 1

Views: 393

Answers (1)

Sweeper
Sweeper

Reputation: 271355

The keyword here is "specific". Swift always finds the most specific overload to call.

Swift first infers that value1 is of type Int, so type(of: value1) is of type Int.Type.

Now we've got a Int.Type as the parameter, Swift looks for an overload that accepts one parameter whose type is exactly Int.Type. It finds one and calls that. The one that accepts a Fooable.Type is not called because it can already call a more specific one that accepts exactly a Int.Type. Here, "specific" means lower down the type hierarchy. Int is considered more specific than Fooable because Int conforms to Fooable.

value3 is inferred to be of type Bool.Type. There is not overload that accepts a Bool.Type, so Swift has to look up the type hierarchy and finds the one that accepts a Fooable.Type. This is the most specific type that you can pass a Bool.Type into.

Upvotes: 3

Related Questions