Ambiguous Use of Operator?

I'm working on a chapter on closures from a book and in it they mention the following:

And finally, you can even omit the parameter list if you want. Swift lets you refer to each parameter by number, starting at zero, like so:

multiplyClosure = {
$0 * $1
}”

I decided to try that myself and typed the following in Swift:

let thisEquals = {
    $0 * $1
}

thisEquals(10, 4)

However, upon doing so, I get the following error message:

Playground execution failed:

error: Deletable Playground 4.playground:2:8: error: ambiguous use of operator '+'
$0 + $1
^

Could someone please explain to me why this is happening? Is there something that I'm doing wrong here? What is meant by "ambiguous use" here and why isn't this code working? Please help. Thank you.

You need to specify the type for the closure:

let thisEquals: (Int, Int) -> Int = { $0 * $1 }

The diagnostic could certainly be improved though.

The problem in thisEquals is that * has multiple definitions. Here are two definitions from the standard library:

public static func * (lhs: Int, rhs: Int) -> Int
public static func * (lhs: Double, rhs: Double) -> Double

Since the definition of thisEquals contains no type information, Swift doesn't know which definition of * to use.

One way to fix it is to specify the type of thisEquals:

let thisEquals: (Int, Int) -> (Int) = {
    $0 * $1
}
1 Like

I'm confused as to why the book lists something so different. Is the code excerpt from the book outdated maybe?

I haven't seen the book so I don't know how multiplyClosure was declared. Perhaps it was declared with a type? For example, this works:

var multiplyClosure: ((Int, Int) -> Int)?
multiplyClosure = { $0 * $1 }

The book lists the following earlier in the text:

In order for the declaration to compile in a playground, you need to provide an initial definition like so:

var multiplyClosure = { (a: Int, b: Int) -> Int in
return a * b
}

Just after that, it completely omits the let kyword, for reasons that I do not understand (is it okay to omit the let keyword in that way?):

...if the closure consists of a single return statement, you can leave out the return keyword, like so:
multiplyClosure = { (a: Int, b: Int) -> Int in
  a * b
}

Immediately after that text, it states the following:

Next, you can use Swift’s type inference to shorten the syntax even more by removing the type information:

multiplyClosure = { (a, b) in
a * b
}

Note that in this code as well, the let keyword is completely omitted again. I don't understand why or if that's normal practice.

Finally, it states the following, (which is the text/code I initially typed in my original post):

And finally, you can even omit the parameter list if you want. Swift lets you refer to each parameter by number, starting at zero, like so:
multiplyClosure = {
$0 * $1
}

This comprises all of/the only code that precedes the code listed in my original post.

The first "var multiplyClosure = " specifies the full type so it's fine. The next two "multiplyClosure =" do not, but they are assigning to a variable that was defined earlier. The type of the variable is already known from the var declaration, and so the type of the closure can be inferred form this.

2 Likes

Yikes, I just realized this closure was assigned to a var (variable) and not to a let (constant). So closures can be assigned to a constant or a variable? Thank you for your help.

Thank you, I understand now. :slight_smile: