Guoye Zhang
Guoye Zhang

Reputation: 519

How to disambiguate functions with differences only in parameter names in Swift

I have the following functions:

func moveThing(thing: AnyObject, toLeft length: Int) {}
func moveThing(thing: AnyObject, toRight length: Int) {}

However, when I pass one of the functions as a parameter, compiler complains about "Ambiguous use of 'moveThing'"

func exec(function: (AnyObject, Int) -> ()) {}
exec(moveThing) // Apparently ambiguous
exec(moveThing as (AnyObject, toLeft: Int) -> ()) // Still ambiguous

How can I solve the ambiguity?

Upvotes: 6

Views: 720

Answers (3)

Scott Levie
Scott Levie

Reputation: 91

I know this is an old thread, but I ran into this related situation recently. Might help somebody.


TLDR

Ultimately I solved the problem by just wrapping the method call in a closure like this:

let cancel: (Text) -> Alert.Button = { .cancel($0) }



Long Winded Explanation

When I type Alert.Button.cancel (from the SwiftUI framework), auto-complete shows me these options:

cancel(action: (() -> Void)?) // 1
cancel(label: Text) // 2
cancel() // 3
cancel(label: Text, action: (() -> Void)?) // 4

Naturally I thought this bit of code should work:

let cancel: (Text) -> Alert.Button = Alert.Button.cancel(_:)

However, the compiler says Cannot convert value of type '((() -> Void)?) -> Alert.Button' to specified type '(Text) -> Alert.Button'. Apparently it translates that signature to mean method 1 instead of method 2.

As it turns out, method 2 does not actually exist. Looking at the actual declarations in Alert.swift we find:

public static func cancel(_ label: Text, action: (() -> Void)? = {}) -> Alert.Button
public static func cancel(_ action: (() -> Void)? = {}) -> Alert.Button

So, cancel(label:) is rendered by auto-complete from cancel(_:action:) because the parameter action has a default value.

Conclusion: I made the mistake of assuming auto-complete was showing me individual method declarations. If the compiler tells you a method signature doesn't match what you expect, check the method declaration.

Upvotes: 1

Guoye Zhang
Guoye Zhang

Reputation: 519

Swift Evolution proposal SE-0021 addressed this by allowing moveThing(_:toLeft:) to disambiguate these functions, and it is implemented in Swift 2.2.

Upvotes: 3

Teemu Kurppa
Teemu Kurppa

Reputation: 4829

An interesting question! I don't think you can at the moment, as it seems that parameter names are not part of the function reference name, though I couldn't find anything from Apple's reference documentation that explicitly dictates this.

Of course, for this particular example, you can use

exec({ moveThing($0, toLeft: $1) } )
exec({ moveThing($0, toRight: $1) } )

but I see what you are after with the simplified example.

Upvotes: 0

Related Questions