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.

It doesn't matter if something is a var or a let (or even if it's a variable at all — it could be a generic parameter, for example) — what matters is that you give the compiler enough information on the type. By just writing a closure as {(a,b) in a * b} (without any further context), you are not saying enough about what types a and b are supposed to be of, so the compiler fails. But if you are assigning it (or passing as an argument or something else) to something that can provide this type information (like in the above example, a variable that already "knows" what type of closure it stores), the compiler infers the types of a and b.

1 Like

Thank you, I understand now. :slight_smile: